2009-04-25 8 views
1

GNU 도구 (gcc, binutils 등)를 사용하여 어셈블리 명령의 모든 항목을 아무 작업으로도 수정할 수 있습니까?명령을 사용하지 않으려 고 시도

0x0: e1a0c00d mov ip, sp 
    0x4: e92dd800 stmdb sp!, {fp, ip, lr, pc} 
    0x8: e24cb004 sub fp, ip, #4 ; 0x4 
    0xc: ebfffffe bl 0 <mcount> 

내가이 마지막 명령어의 주소를 기록, 다음 코드

0x0: e1a0c00d mov ip, sp 
    0x4: e92dd800 stmdb sp!, {fp, ip, lr, pc} 
    0x8: e24cb004 sub fp, ip, #4 ; 0x4 
    0xc: e1a00000 nop   (mov r0,r0) 
에 같은 NOP로 변경하려면 : 특히, -pg 옵션 GCC는 다음 조립 (ARM)를 생성

리눅스 커널은 런타임시 이와 비슷한 작업을 수행 할 수 있지만 빌드 타임 솔루션을 찾고 있습니다.

답변

4

이것은 RISC-ish 고정 길이 명령어 포맷을 사용하는 것보다 확실히 쉽습니다. x86.

오브젝트 파일을 열고 .text 섹션 내에서 명령어를 수정하고 제공된 API를 사용하여 다시 작성하려면 libelf (멋진 튜토리얼 : http://people.freebsd.org/~jkoshy/download/libelf/article.html) 또는 libbfd (http://sourceware.org/binutils/docs-2.19/bfd/index.html)를 사용하는 것이 상대적으로 간단해야합니다. 노력의 가치가 있는지 없는지는 비 기술적 인 고려 사항에 달려 있습니다 (나는 다소 호기심이 많습니다 ...).

크로스 개발 환경에서 작동해야하는 경우 libelf 또는 libbfd를 사용하는 데 약간의 주름이있을 수 있습니다.

+0

포인트가 유효한 동안 x86의 'nop'은 1 바이트 명령어이므로 제거 할 가변 길이 명령어를 통해 필요한만큼 많은 것을 쓸 수 있습니다. –

+1

가변 길이 명령어의 경우 문제가되는 부분은 명령어 패턴을 검색하는 것입니다. 주어진 바이트 오프셋이 명령어를 디코딩하지 않고 명령어의 시작인지 여부를 알 수 없기 때문에 명령어 패턴을 no-op로 변환해야합니다. 그 오프셋 전에 지침. 바이너리의 리버스 엔지니어링을 때로는 (또는 적어도 방해하는 데 사용되는) 명령어의 중간으로 분기하는 것과 같은 똑똑한 코드를 작성한 어셈블러 트릭을 고려해 보면 더욱 심각합니다. –

+0

참; 나는 그 방향에서 그것에 대해 생각하지 않았습니다. 좋은 지적. –

6

gcc -S 코드를 컴파일하여 개체 파일이나 실행 파일로 완전히 컴파일하는 대신 어셈블러 목록을 출력 할 수 있습니다. 그런 다음 no-ops로 원하는 명령어를 바꾸고 (예 : sed 사용) 컴파일을 계속하십시오.

원래 소스 코드가없는 오브젝트 파일이나 라이브러리에도이 작업을 수행하려는 경우 objdump(1)과 같은 도구를 사용하여 해체하고 지침의 주소를 가져와야합니다 당신은 바꾸려고합니다. 그런 다음 해당 파일 파일 내의 오프셋을 찾으려면 개체 파일 헤더를 구문 분석 한 다음 개체 파일에서 직접 no-ops로 컴퓨터 지침을 바꿉니다. 이것은 조금 까다 롭지 만 할 수 있습니다.

+0

대체 할 때 데이터를 겹쳐 쓰지 않도록하십시오 (예 : 원본의 이진 데이터 및 문자열). – strager

+0

사실, 'gcc -S'는 데이터에 대한 어셈블리 코드 (제품 데이터 지시어)를 생성하지 않지만 objdump는 일반적으로 코드를 포함하는 세그먼트 만 분해 할만큼 똑똑합니다. 그러나이 두 기술 모두 런타임 코드 생성 또는 자체 수정 코드 그러나 그것은 단지 문제를 요구하고 있습니다. –