박리된 애플리케이션의 주요 기능을 분해하는 방법은 무엇입니까?
제가 아래 애플리케이션을 컴파일하여 해당 심볼을 제거했다고 가정해 보겠습니다.
#include <stdio.h>
int main()
{
printf("Hello\n");
}
빌드 절차:
gcc -o hello hello.c
strip --strip-unneeded hello
애플리케이션이 벗겨지지 않았다면 메인 기능을 분해하는 것이 쉬울 것입니다.하지만, 저는 제거된 애플리케이션의 주요 기능을 분해하는 방법을 전혀 모릅니다.
(gdb) disas main
No symbol table is loaded. Use the "file" command.
(gdb) info line main
Function "main" not defined.
제가 어떻게 할 수 있을까요?그게 가능할까요?
참고: 이 작업은 GDB에서만 수행해야 합니다.objdump는 잊어버려요.내가 코드에 접근할 수 없다고 가정합니다.
단계별로 예를 들어주시면 감사하겠습니다.
좋아요, 여기 제 이전 답변의 큰 판이 있습니다.이제 방법을 찾은 것 같아요.
당신(아직 :)은 다음과 같은 구체적인 문제를 가지고 있습니다.
(gdb) disas main
No symbol table is loaded. Use the "file" command.
이제 코드를 컴파일하면 (제가 추가했습니다.return 0마지막에), 당신은 이해할 것입니다.gcc -S:
pushq %rbp
movq %rsp, %rbp
movl $.LC0, %edi
call puts
movl $0, %eax
leave
ret
이제 바이너리가 다음과 같은 정보를 제공하는 것을 확인할 수 있습니다.
줄무늬:
(gdb) info files
Symbols from "/home/beco/Documents/fontes/cpp/teste/stackoverflow/distrip".
Local exec file:
`/home/beco/Documents/fontes/cpp/teste/stackoverflow/distrip', file type elf64-x86-64.
Entry point: 0x400440
0x0000000000400238 - 0x0000000000400254 is .interp
...
0x00000000004003a8 - 0x00000000004003c0 is .rela.dyn
0x00000000004003c0 - 0x00000000004003f0 is .rela.plt
0x00000000004003f0 - 0x0000000000400408 is .init
0x0000000000400408 - 0x0000000000400438 is .plt
0x0000000000400440 - 0x0000000000400618 is .text
...
0x0000000000601010 - 0x0000000000601020 is .data
0x0000000000601020 - 0x0000000000601030 is .bss
은 여서가장중항목은입니다..text코드의 어셈블리 시작에 대한 일반적인 이름이며, 아래의 메인 설명을 통해 크기로 보아 메인이 포함되어 있음을 알 수 있습니다.이를 분해하면 __libc_start_main에 대한 호출이 표시됩니다.가장 중요한 것은 실제 코드인 양호한 진입점을 분해하는 것입니다(DATA를 CODE로 변경하는 것은 오해의 소지가 없습니다).
disas 0x0000000000400440,0x0000000000400618
Dump of assembler code from 0x400440 to 0x400618:
0x0000000000400440: xor %ebp,%ebp
0x0000000000400442: mov %rdx,%r9
0x0000000000400445: pop %rsi
0x0000000000400446: mov %rsp,%rdx
0x0000000000400449: and $0xfffffffffffffff0,%rsp
0x000000000040044d: push %rax
0x000000000040044e: push %rsp
0x000000000040044f: mov $0x400540,%r8
0x0000000000400456: mov $0x400550,%rcx
0x000000000040045d: mov $0x400524,%rdi
0x0000000000400464: callq 0x400428 <__libc_start_main@plt>
0x0000000000400469: hlt
...
0x000000000040046c: sub $0x8,%rsp
...
0x0000000000400482: retq
0x0000000000400483: nop
...
0x0000000000400490: push %rbp
..
0x00000000004004f2: leaveq
0x00000000004004f3: retq
0x00000000004004f4: data32 data32 nopw %cs:0x0(%rax,%rax,1)
...
0x000000000040051d: leaveq
0x000000000040051e: jmpq *%rax
...
0x0000000000400520: leaveq
0x0000000000400521: retq
0x0000000000400522: nop
0x0000000000400523: nop
0x0000000000400524: push %rbp
0x0000000000400525: mov %rsp,%rbp
0x0000000000400528: mov $0x40062c,%edi
0x000000000040052d: callq 0x400418 <puts@plt>
0x0000000000400532: mov $0x0,%eax
0x0000000000400537: leaveq
0x0000000000400538: retq
__libc_start_main에 대한 호출은 첫 번째 인수로 main()에 대한 포인터를 가져옵니다.따라서 호출 직전 스택의 마지막 인수가 기본() 주소입니다.
0x000000000040045d: mov $0x400524,%rdi
0x0000000000400464: callq 0x400428 <__libc_start_main@plt>
여기 0x400524가 있습니다(이미 알고 있음).이제 중단점을 설정하고 다음을 시도합니다.
(gdb) break *0x400524
Breakpoint 1 at 0x400524
(gdb) run
Starting program: /home/beco/Documents/fontes/cpp/teste/stackoverflow/disassembly/d2
Breakpoint 1, 0x0000000000400524 in main ()
(gdb) n
Single stepping until exit from function main,
which has no line number information.
hello 1
__libc_start_main (main=<value optimized out>, argc=<value optimized out>, ubp_av=<value optimized out>,
init=<value optimized out>, fini=<value optimized out>, rtld_fini=<value optimized out>,
stack_end=0x7fffffffdc38) at libc-start.c:258
258 libc-start.c: No such file or directory.
in libc-start.c
(gdb) n
Program exited normally.
(gdb)
이제 다음을 사용하여 분해할 수 있습니다.
(gdb) disas 0x0000000000400524,0x0000000000400600
Dump of assembler code from 0x400524 to 0x400600:
0x0000000000400524: push %rbp
0x0000000000400525: mov %rsp,%rbp
0x0000000000400528: sub $0x10,%rsp
0x000000000040052c: movl $0x1,-0x4(%rbp)
0x0000000000400533: mov $0x40064c,%eax
0x0000000000400538: mov -0x4(%rbp),%edx
0x000000000040053b: mov %edx,%esi
0x000000000040053d: mov %rax,%rdi
0x0000000000400540: mov $0x0,%eax
0x0000000000400545: callq 0x400418 <printf@plt>
0x000000000040054a: mov $0x0,%eax
0x000000000040054f: leaveq
0x0000000000400550: retq
0x0000000000400551: nop
0x0000000000400552: nop
0x0000000000400553: nop
0x0000000000400554: nop
0x0000000000400555: nop
...
이것이 기본적으로 해결책입니다.
BTW, 이것은 작동하는지 보기 위해 다른 코드입니다.그것이 위의 어셈블리가 조금 다른 이유입니다.위의 코드는 다음 c 파일에서 가져온 것입니다.
#include <stdio.h>
int main(void)
{
int i=1;
printf("hello %d\n", i);
return 0;
}
하지만!
이 방법이 작동하지 않는 경우에도 몇 가지 힌트를 얻을 수 있습니다.
이제부터 모든 기능의 시작 부분에 중단점을 설정해야 합니다.은 들은바앞있다습니에 .ret또는leave첫 번째 진입점은 다음과 같습니다..text시작이지만.이것은 조립 시작이지만 메인은 아닙니다.
문제는 중단점이 항상 프로그램을 실행할 수 있는 것은 아니라는 것입니다.아▁the에 있는 처럼..text:
(gdb) break *0x0000000000400440
Breakpoint 2 at 0x400440
(gdb) run
Starting program: /home/beco/Documents/fontes/cpp/teste/stackoverflow/disassembly/d2
Breakpoint 2, 0x0000000000400440 in _start ()
(gdb) n
Single stepping until exit from function _start,
which has no line number information.
0x0000000000400428 in __libc_start_main@plt ()
(gdb) n
Single stepping until exit from function __libc_start_main@plt,
which has no line number information.
0x0000000000400408 in ?? ()
(gdb) n
Cannot find bounds of current function
따라서 여러분은 길을 찾을 때까지 계속해서 시도하고 중단점을 다음과 같이 설정해야 합니다.
0x400440
0x40046c
0x400490
0x4004f4
0x40051e
0x400524
다른 답변에서는 다음과 같은 정보를 유지해야 합니다.
스트라이프되지 않은 버전의 파일에서 다음을 확인할 수 있습니다.
(gdb) disas main
Dump of assembler code for function main:
0x0000000000400524 <+0>: push %rbp
0x0000000000400525 <+1>: mov %rsp,%rbp
0x0000000000400528 <+4>: mov $0x40062c,%edi
0x000000000040052d <+9>: callq 0x400418 <puts@plt>
0x0000000000400532 <+14>: mov $0x0,%eax
0x0000000000400537 <+19>: leaveq
0x0000000000400538 <+20>: retq
End of assembler dump.
이제 우리는 메인이0x0000000000400524,0x0000000000400539동일한 오프셋을 사용하여 스트라이프 이진수를 살펴보면 동일한 결과를 얻을 수 있습니다.
(gdb) disas 0x0000000000400524,0x0000000000400539
Dump of assembler code from 0x400524 to 0x400539:
0x0000000000400524: push %rbp
0x0000000000400525: mov %rsp,%rbp
0x0000000000400528: mov $0x40062c,%edi
0x000000000040052d: callq 0x400418 <puts@plt>
0x0000000000400532: mov $0x0,%eax
0x0000000000400537: leaveq
0x0000000000400538: retq
End of assembler dump.
따라서 (기호가 있는 다른 코드를 사용하는 것과 같이) 메인이 시작되는 부분에 대한 팁을 얻을 수 없는 한, 다른 방법은 첫 번째 어셈블리 지침에 대한 정보를 얻을 수 있으므로 특정 위치에서 분해하고 일치하는지 확인할 수 있습니다.코드에 대한 액세스 권한이 전혀 없는 경우에도 ELF 정의를 읽어 코드에 표시할 섹션 수를 파악하고 계산된 주소를 사용할 수 있습니다.그래도 코드의 섹션에 대한 정보가 필요합니다!
그건 힘든 일이야, 친구!행운을 빕니다.
베코
하는게 어때요?info files섹션 목록(주소 포함)을 가져오고 거기서 이동합니까?
예:
gdb) info files
Symbols from "/home/bob/tmp/t".
Local exec file:
`/home/bob/tmp/t', file type elf64-x86-64.
Entry point: 0x400490
0x0000000000400270 - 0x000000000040028c is .interp
0x000000000040028c - 0x00000000004002ac is .note.ABI-tag
....
0x0000000000400448 - 0x0000000000400460 is .init
....
디스어셈블.init:
(gdb) disas 0x0000000000400448,0x0000000000400460
Dump of assembler code from 0x400448 to 0x400460:
0x0000000000400448: sub $0x8,%rsp
0x000000000040044c: callq 0x4004bc
0x0000000000400451: callq 0x400550
0x0000000000400456: callq 0x400650
0x000000000040045b: add $0x8,%rsp
0x000000000040045f: retq
그럼 나머지는 분해하세요.
만약 제가 당신이라면, 그리고 당신의 실행 파일이 만들어진 것과 같은 GCC 버전을 가지고 있다면, 저는 더미 비스트립 실행 파일에서 호출되는 함수들의 순서를 조사할 것입니다.통화 순서는 아마도 대부분의 일반적인 경우에 유사하므로 시작 순서를 끝까지 가는 데 도움이 될 수 있습니다.main그에 비해그러나 최적화는 아마도 방해가 될 것입니다.
만약 당신의 바이너리가 벗겨지고 최적화된다면,main바이너리에 "프로시저"로 존재하지 않을 수 있습니다. 이러한 유형의 프로시저보다 훨씬 더 나은 방법은 없을 수 있습니다.
파라딘 프로젝트의 언스트립이라는 새로운 무료 도구가 있습니다(완전 공개:저는 이 프로젝트에서 당신의 프로그램 바이너리를 다시 작성하고 심볼 정보를 추가하며, 당신을 위해 벗겨진 엘프 바이너리의 모든 (또는 거의 모든) 기능을 매우 정확하게 복구할 것입니다.주 기능을 "주"로 식별하지는 않지만 주 기능을 찾을 수 있으며, 위에서 이미 언급한 휴리스틱을 적용하여 어떤 기능이 주 기능인지 파악할 수 있습니다.
http://www.paradyn.org/html/tools/unstrip.html
죄송합니다만 이것은 agdb 전용 솔루션이 아닙니다.
IIRC,x/i <location>당신의 친구입니다.물론 어떤 위치에서 분해할 것인지 스스로 결정해야 합니다.
언급URL : https://stackoverflow.com/questions/5475790/how-to-disassemble-the-main-function-of-a-stripped-application
'programing' 카테고리의 다른 글
| 모건 로거는 어떻게 사용하나요? (0) | 2023.07.24 |
|---|---|
| GitHub - 작성자별 커밋 나열 (0) | 2023.07.24 |
| 분기가 없는 Git 커밋 나열 및 삭제(Dangling?) (0) | 2023.07.19 |
| ASP.NET의 HttpHandler란? (0) | 2023.07.19 |
| pip 버전 자체를 아는 방법 (0) | 2023.07.19 |