지정된 실행 파일 외부의 단일 단계 어셈블리 코드에 gdb를 사용하면 "현재 함수의 범위를 찾을 수 없습니다"오류가 발생합니다.


86

나는 gdb의 대상 실행 파일 외부에 있으며 해당 대상에 해당하는 스택도 없습니다. 어쨌든 나는 x86 어셈블리의 전문가가 아니기 때문에 어셈블리 코드에서 무슨 일이 일어나고 있는지 확인할 수 있도록 한 단계 씩 진행하고 싶습니다. 불행히도 gdb는이 간단한 어셈블리 수준 디버깅을 거부합니다. 적절한 중단 점을 설정하고 중지 할 수 있지만 한 단계 진행하자마자 gdb는 "현재 함수의 경계를 찾을 수 없습니다"라는 오류를보고하고 EIP는 변경되지 않습니다.

추가 세부 사항:

기계 코드는 gcc asm 문에 의해 생성되었으며 objdump -d의 출력에서 ​​실행중인 커널 메모리 위치에 복사했습니다. 로더를 사용하여 객체 코드를 재배치 된 주소로로드하는 간단한 방법은 신경 쓰지 않지만로드는 커널 모듈에서 수행해야합니다.

또 다른 대안은 gdb에 제공 할 가짜 커널 모듈 또는 디버그 정보 파일을 생성하여이 영역이 프로그램 코드 내에 있다고 믿도록하는 것입니다. gdb는 커널 실행 파일 자체에서 잘 작동합니다.

(정말 알고 싶은 사람들을 위해 런타임에 VMware VM 내부의 Linux 커널 데이터 공간에 코드를 삽입하고 VMware Workstation의 내장 gdb 스텁을 통해 커널을 원격 디버깅하는 gdb에서 디버깅합니다. 참고 커널을 작성하는 것이 아닙니다. 익스플로잇; 저는 프로토 타입을 작성하는 보안 대학원생입니다.)

(내 어셈블리 내부의 각 명령어에 중단 점을 설정할 수 있습니다. 이것은 작동하지만 x86 어셈블리 명령어의 크기가 다양하고 재부팅 할 때마다 어셈블리 위치가 변경되기 때문에 시간이 지나면 상당히 힘들 것입니다.)


영리한 ksplice.com 사람들은 "가짜"커널 모듈을 조립하고로드하여 커널에 데이터와 코드를 주입합니다. 그리고 그들이 그것을 할 수 있다면 왜 당신은 할 수 없습니까? ;-)
ephemient

답변:


116

당신이 사용할 수있는 stepi 또는 nexti(이는로 축약 할 수 있습니다 si또는 ni컴퓨터 코드를 통해 단계).


1
와. 돌이켜 보면 어떻게 stepi를 잊었는지 모르겠습니다. 나는 gdb에 단계가 어셈블리 명령으로 되돌아 갈 소스 코드가 없기 때문에 방금 가정했다고 생각합니다.
Paul

1
참고 : 어셈블리 프로그램에는 "break main", "run"을 입력 할 수없는 경우가 많습니다. 대신 "layout asm", "start"를 입력합니다. 나는 아래 메시지를 읽음으로써 이것을 얻었지만이 게시물을 읽는 다른 사람은 인내심이 없을 수 있습니다.
Dmitry

1
@Dmitry이 start동등 tbreak main하였다 run(참고 : tbreak대신 break)
루슬란

151

대신 gdb, 실행 gdbtui. 또는 스위치로 실행 gdb하십시오 -tui. 또는 C-x C-a입력 후를 누릅니다 gdb. 이제 GDB의 TUI 모드에 있습니다.

Enter 키 layout asm를 눌러 상단 창 디스플레이 어셈블리를 만듭니다. 디버깅하는 동안 프레임을 변경하거나 스크롤 할 수도 있지만 자동으로 명령 포인터를 따릅니다. 을 눌러 단일 키 C-x s모드로 들어가십시오. 여기서 run continue up down finish등은 단일 키로 축약되어 프로그램을 매우 빠르게 진행할 수 있습니다.

   + ------------------------------------------------- -------------------------- +
B +> | 0x402670 <main> 푸시 % r15 |
   | 0x402672 <main + 2> mov % edi, % r15d |
   | 0x402675 <main + 5> 푸시 % r14 |
   | 0x402677 <main + 7> 푸시 % r13 |
   | 0x402679 <main + 9> mov % rsi, % r13 |
   | 0x40267c <main + 12> 푸시 % r12 |
   | 0x40267e <main + 14> % rbp 푸시 |
   | 0x40267f <main + 15> % rbx 푸시 |
   | 0x402680 <메인 +16> 하위 $ 0x438, % rsp |
   | 0x402687 <main + 23> mov (% rsi), % rdi |
   | 0x40268a <main + 26> movq $ 0x402a10,0x400 (% rsp) |
   | 0x402696 <main + 38> movq $ 0x0,0x408 (% rsp) |
   | 0x4026a2 <main + 50> movq $ 0x402510,0x410 (% rsp) |
   + ------------------------------------------------- -------------------------- +
자식 프로세스 21518 In : 메인 라인 : ?? PC : 0x402670
(gdb) 파일 / opt / j64-602 / bin / jconsole
/ opt / j64-602 / bin / jconsole에서 기호 읽기 ... 완료.
(디버깅 기호가 없음) ... 완료.
(gdb) 레이아웃 asm
(gdb) 시작
(gdb)

26

여기서 할 수있는 가장 유용한 것은 R Samuel Klatchko의 답변에서 이미 제안 된대로 display/i $pc사용하기 전에 stepi입니다. 이것은 매번 프롬프트를 인쇄하기 직전에 gdb에게 현재 명령어를 디스 어셈블하도록 지시합니다. 그런 다음 Enter 키를 계속 눌러 stepi명령 을 반복 할 수 있습니다 .

(자세한 내용 은 다른 질문에 대한 내 답변을 참조하십시오. 해당 질문의 컨텍스트는 달랐지만 원칙은 동일합니다.)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.