런타임 코드 수정 (런타임에 자체 코드를 수정하는 프로그램)에 대한 합법적 인 (스마트 한) 사용을 생각할 수 있습니까?
최신 운영 체제는 바이러스가 탐지를 피하기 위해이 기술을 사용했기 때문에이를 수행하는 프로그램을 눈살을 찌푸리는 것처럼 보입니다.
내가 생각할 수있는 것은 컴파일 타임에 알 수없는 무언가를 런타임에 알고 일부 코드를 제거하거나 추가하는 일종의 런타임 최적화입니다.
런타임 코드 수정 (런타임에 자체 코드를 수정하는 프로그램)에 대한 합법적 인 (스마트 한) 사용을 생각할 수 있습니까?
최신 운영 체제는 바이러스가 탐지를 피하기 위해이 기술을 사용했기 때문에이를 수행하는 프로그램을 눈살을 찌푸리는 것처럼 보입니다.
내가 생각할 수있는 것은 컴파일 타임에 알 수없는 무언가를 런타임에 알고 일부 코드를 제거하거나 추가하는 일종의 런타임 최적화입니다.
답변:
코드 수정에 대한 유효한 경우가 많이 있습니다. 런타임에 코드를 생성하면 다음과 같은 경우에 유용 할 수 있습니다.
때때로 코드는 런타임에 코드로 변환됩니다 (이를 동적 이진 변환 이라고 함 ).
코드 수정을 사용하여 명령어 세트의 제한을 해결할 수 있습니다.
더 많은 코드 수정 사례 :
이것은 컴퓨터 그래픽, 특히 최적화 목적의 소프트웨어 렌더러에서 수행되었습니다. 런타임에 많은 매개 변수의 상태가 검사되고 최적화 된 버전의 래스터 라이저 코드가 생성되어 (잠재적으로 많은 조건부 제거) 삼각형과 같은 그래픽 프리미티브를 훨씬 더 빠르게 렌더링 할 수 있습니다.
한 가지 유효한 이유는 asm 명령어 세트에 필요한 명령어가 없기 때문에 직접 구축 할 수 있습니다. 예 : x86에서는 레지스터의 변수에 인터럽트를 생성하는 방법이 없습니다 (예 : ax에서 인터럽트 번호로 인터럽트 생성). opcode에 코딩 된 const 번호 만 허용되었습니다. 자가 수정 코드를 사용하면이 동작을 모방 할 수 있습니다.
일부 컴파일러는 정적 변수 초기화에 사용하여 후속 액세스에 대한 조건부 비용을 피했습니다. 즉, 처음 실행될 때 no-ops로 해당 코드를 덮어 써서 "이 코드를 한 번만 실행"을 구현합니다.
많은 경우가 있습니다.
일부 OS의 보안 모델은 자체 수정 코드가 루트 / 관리자 권한 없이는 실행할 수 없음을 의미하므로 범용 사용에는 비실용적입니다.
Wikipedia에서 :
엄격한 W ^ X 보안을 사용하는 운영 체제에서 실행되는 응용 프로그램 소프트웨어는 쓰기가 허용 된 페이지에서 명령을 실행할 수 없습니다. 운영 체제 자체 만 명령을 메모리에 쓰고 나중에 해당 명령을 실행할 수 있습니다.
이러한 OS에서는 Java VM과 같은 프로그램도 JIT 코드를 실행하기 위해 루트 / 관리자 권한이 필요합니다. (자세한 내용은 http://en.wikipedia.org/wiki/W%5EX 참조)
합성 OS는 기본적으로 부분적으로 API 호출에 대한 프로그램을 평가하고, 그 결과로 OS 코드를 교체했다. 주요 이점은 많은 오류 검사가 사라 졌다는 것입니다 (프로그램이 OS에 어리석은 작업을 요청하지 않을 경우 검사 할 필요가 없기 때문입니다).
예, 이것이 런타임 최적화의 예입니다.
몇 년 전 나는 아침에자가 수정 코드를 디버깅하려고하는데, 한 명령이 다음 명령의 대상 주소를 변경했습니다. 즉, 분기 주소를 계산하고있었습니다. 어셈블리 언어로 작성되었으며 프로그램을 한 번에 하나씩 단계별로 실행했을 때 완벽하게 작동했습니다. 그러나 프로그램을 실행했을 때 실패했습니다. 결국, 나는 기계가 메모리에서 2 개의 명령어를 가져오고 있다는 것을 깨달았고 (명령이 메모리에 배치 되었기 때문에) 내가 수정하고 있던 명령어를 이미 가져 왔으므로 기계는 수정되지 않은 (잘못된) 버전의 명령어를 실행하고있었습니다. 물론 디버깅 할 때는 한 번에 하나의 명령 만 수행했습니다.
내 요점은 자체 수정 코드는 테스트 / 디버그하기가 매우 까다로울 수 있으며 종종 하드웨어 또는 가상 머신의 동작에 대한 숨겨진 가정을 가지고 있습니다. 더욱이 시스템은 (현재) 멀티 코어 머신에서 실행되는 다양한 스레드 / 프로세스간에 코드 페이지를 공유 할 수 없습니다. 이것은 가상 메모리 등에 대한 많은 이점을 무효화합니다. 또한 하드웨어 수준에서 수행 된 분기 최적화를 무효화합니다.
(참고-저는 자체 수정 코드 범주에 JIT를 포함하지 않았습니다. JIT는 코드의 한 표현에서 대체 표현으로 변환하고 있으며 코드를 수정하는 것이 아닙니다)
대체로 그것은 단지 나쁜 생각 일뿐입니다. 정말 깔끔하고, 정말 모호하지만 정말 나쁩니다.
물론-당신이 가진 모든 것이 8080과 ~ 512 바이트의 메모리라면 당신은 그러한 관행에 의지해야 할 수도 있습니다.
하드웨어와 소프트웨어간에 논리적 차이가 없다는 오래된 밤나무를 알고 있습니다. 코드와 데이터간에 논리적 차이가 없다고 말할 수도 있습니다.
자가 수정 코드 란 무엇입니까? 데이터가 아닌 명령으로 해석 될 수 있도록 실행 스트림에 값을 넣는 코드입니다. 물론 실제로 차이가 없다는 이론적 관점이 함수 언어에 있습니다. 나는 e가 동등한 지위를 가정하지 않고 명령형 언어와 컴파일러 / 통역사에서 간단한 방식으로 이것을 할 수 있다고 말하고있다.
제가 말하고있는 것은 데이터가 프로그램 실행 경로를 변경할 수 있다는 실제적인 의미입니다 (어떤 의미에서는 이것은 매우 분명합니다). 나는 프로그램이 명령에서 명령으로 이동하는 방식과 같이 구문 분석에서 통과하는 테이블 (데이터 배열)을 생성하고 상태에서 상태로 이동 (다른 변수도 수정)하는 컴파일러 컴파일러와 같은 것을 생각하고 있습니다. , 프로세스에서 변수 수정.
따라서 컴파일러가 코드 공간을 생성하고 완전히 분리 된 데이터 공간 (힙)을 참조하는 일반적인 인스턴스에서도 실행 경로를 명시 적으로 변경하기 위해 데이터를 수정할 수 있습니다.
한 가지 사용 사례는 바이러스 백신 프로그램을 테스트하기위한 합법적 인 DOS 실행 가능 COM 파일 인 EICAR 테스트 파일 입니다.
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
실행 파일은 인코딩 가능한 명령어의 수를 크게 제한하는 [21h-60h, 7Bh-7Dh] 범위의 인쇄 / 입력 가능한 ASCII 문자 만 포함해야하므로 자체 코드 수정을 사용해야합니다.
DOS에서 부동 소수점 연산 디스패치에도 사용됩니다.
일부 컴파일러는 CD xx
x87 부동 소수점 명령어 대신 0x34-0x3B 범위의 xx 를 방출 합니다. CD
명령에 대한 opcode 이므로 int
인터럽트 34h-3Bh로 점프하여 x87 보조 프로세서를 사용할 수없는 경우 소프트웨어에서 해당 명령을 에뮬레이트합니다. 그렇지 않으면 인터럽트 처리기가이 2 바이트를로 대체하여 9B Dx
나중에 실행이 에뮬레이션없이 x87에 의해 직접 처리됩니다.
지속적으로 업데이트되는 데이터베이스에 대해 통계 분석을 실행합니다. 사용 가능한 새로운 데이터를 수용하기 위해 코드가 실행될 때마다 통계 모델이 작성되고 다시 작성됩니다.
이것이 사용될 수있는 시나리오는 학습 프로그램입니다. 사용자 입력에 대한 응답으로 프로그램은 새로운 알고리즘을 학습합니다.
Java에서이를 수행하는 방법에 대한 질문이 있습니다. Java 코드의 자체 수정 가능성은 무엇입니까?
이것의 가장 좋은 버전은 Lisp 매크로 일 것입니다. 전처리 기일 뿐인 C 매크로와 달리 Lisp를 사용하면 항상 전체 프로그래밍 언어에 액세스 할 수 있습니다. 이것은 lisp에서 가장 강력한 기능에 대한 것이며 다른 언어에는 존재하지 않습니다.
나는 결코 전문가가 아니지만 lisp 녀석 중 한 명이 그것에 대해 이야기하게하십시오! 그들이 Lisp가 주변에서 가장 강력한 언어이고 현명한 사람들은 그들이 옳다고 말하는 이유가 있습니다.