disp $esp
disp $ebp
disp $eip
disp /i $eip
disp /4xw $esp
disp /4xw $ebp
disp /i $pc
-
if문을 c언어로 작성해 컴파일했을때
0x080484b3 <+6>: movl $0x1,-0x4(%ebp)
0x080484ba <+13>: cmpl $0x1,-0x4(%ebp)
0x080484be <+17>: jne 0x80484d0 <main+35>
=> 처음보는 cmpl, jne 명령어가 나온다
CMP(compare) 명령어
- 두 개의 대상을 더해서 저장한다
- at&t : cmpl 1피연산자, 2피연산자
- intel : cmp 2피연산자, 1피연산자
- 2피연산자에서 1피연산자를 뺀 값이 0인지 확인하여 결과를 반환한다
- 뺀 값이 0이면 ZF flag에 1이 설정된다 [ ZF ]
JMP 명령어
- 무조건 점프
JNE 명령어 (Jump if not equal)
- 조건 분기 명령어
- 비교나 테스트의 값이 같지 않으면(또는, SF와 OF가 다를때) 점프한다
(SF: 음수일 때, OF: 부호있는 연산에서 오버플로우가 발생했을 때)
JE 명령어
- 조건 분기 명령어
- 비교나 테스트의 값이 같으면 점프한다
그외
Jz (왼쪽인자가 0이라면 점프) Jnz (왼쪽인자가 0이 아니면 점프)
JS(음수(플래그 설정)면 점프) JNS(양수이면 점프)
JG(왼쪽 인자값이 오른쪽 인자값보다 크면 점프) JGE(왼쪽 인자값이 오른쪽 인자값보다 작으면 점프)
JL(왼쪽 인자값이 오른쪽 인자값보다 작으면 점프) JLE(왼쪽 인자값이 오른쪽 인자값보다 작거나 같으면 점프)
<+17>: jne 0x80484d0 <main+35></main+35>
...
<+35>: mov $0x0,%eax
=> 비교가 같지 않으면 main+35로 이동한다는 뜻
ni로 분석을 해도, ZF 플래그는 직접 꺼내 볼 수는 없다
ZF 플래그는 eflags에 속해있으므로 eflags를 확인해야 한다
(gdb) i r eflags
eflags 0x246 [ PF ZF IF ]
1. 비교값이 1과 같다
(gdb) ni
x/i $eip
=> 0x80484be <main+17>: jne 0x80484d0 <main+35>
(gdb) ni
x/i $eip
=> 0x80484c0 <main+19>: pushl -0x4(%ebp)
→ ZF 플래그 설정이 되어서 점프하지 않고 순서대로 실행됨
1. 비교값이 1과 같지 않다
(gdb) ni
x/i $eip
=> 0x80484be <main+17>: jne 0x80484d0 <main+35>
(gdb) ni
x/i $eip
=> 0x80484d0 <main+35>: mov $0x0,%eax
→ ZF 플래그 설정이 되지 않아 35번 라인으로 점프되었다
(gdb) ni
x/i $eip
=> 0x80484d0 <main+35>: push $0x8048583
(gdb) x/s 0x8048583
0x8048583: "program end ..."
=> printf 내용 확인
실습) for문
0x080484c1 <+20>: jmp 0x80484d7 <main+42>
0x080484c3 <+22>: pushl -0x4(%ebp)
0x080484c6 <+25>: push $0x804858c
0x080484cb <+30>: call 0x8048350 <printf@plt>
0x080484d0 <+35>: add $0x8,%esp
0x080484d3 <+38>: addl $0x1,-0x4(%ebp)
0x080484d7 <+42>: cmpl $0x2,-0x4(%ebp)
0x080484db <+46>: jle 0x80484c3 <main+22>
=> jmp 42라인으로 무조건 점프한다
for문 조건을 비교하여, jle 22라인에 다시 조건식 점프
소스코드 : for(i = 0; i < 3; i++)
* JLE : 왼쪽 인자값이 오른쪽 인자값보다 작거나 같다면 jump
조건에 맞지 않을때까지 계속 반복하고 더 이상 점프하지 않게 되면
0x080484dd <+48>: push $0x8048593
자연스럽게 다음 코드로 넘어가게 된다
올리디버거Ollydbg 사용
윈도우에서 실행파일을 분석할 수 있는 무료 디버거 툴
다운로드 : http://ollydbg.de/odbg110.zip
Dev-c++ 설치
다운로드 : https://sourceforge.net/projects/orwelldevcpp/files/latest/download
이렇게 해서 나온 exe 파일을 분석
00401500 /$ 55 push ebp ; main 함수의 시작 (프롤로그) 00401501 |. 89E5 mov ebp,esp 00401503 |. 83E4 F0 and esp,FFFFFFF0 00401506 |. 83EC 20 sub esp,20 00401509 |. E8 82090000 call test-1.00401E90 0040150E |. C74424 1C 01000000 mov dword ptr ss:[esp+1C],1 ; || 00401516 |. 8B4424 1C mov eax,dword ptr ss:[esp+1C] ; || 0040151A |. 894424 04 mov dword ptr ss:[esp+4],eax ; || 0040151E |. C70424 00404000 mov dword ptr ss:[esp],test-1.00404000 ; ||ASCII "i = %d " 00401525 |. E8 DE100000 call <jmp.&msvcrt.printf> ; |\printf 0040152A |. C70424 09404000 mov dword ptr ss:[esp],test-1.00404009 ; |ASCII "program end..." 00401531 |. E8 DA100000 call <jmp.&msvcrt.puts> ; \puts 00401536 |. B8 00000000 mov eax,0 0040153B |. C9 leave 0040153C \. C3 retn ; main 함수의 끝 (에필로그) |
=> 소스 복사 붙여넣기시
f2 브레이크 포인트 설정, f9 브레이크 포인트까지 실행,
f7 함수 내부로 들어가 실행(si), f8 한라인씩 실행(ni)
hex dump를 확인할 수 있다
단축키 : Ctrl + f2 = 재시작
같은 의미의 코드지만,
리눅스에서는 jne 명령어를 사용하고
윈도우에서는 jnz 명령어를 사용하고 있다.
(jne : 테스트값이 같지 않으면 점프
jnz : 왼쪽 인자(테스트값) 0이 아니면 점프)
=> Z 플래그가 1로 셋팅되었다 ( cmp 연산 값이 0이라는 뜻)
윈도우는 sub 20으로 처음부터 모든 메모리 공간을 확보했고 로키8처럼 add로 다시 복구하지 않는다
* 장점 : 실시간 수정해서 원하는 코드를 넣고 빼고 할 수 있음
mov eax, 12345678
mov ax, 77
mov al, 1
mov ah, 2
=> 12345678
=> 12340077
=> 12340001
=> 12340201
→ eax는 8바이트, ax는 4바이트, al은 ax의 오른쪽이고 ah는 ax의 왼쪽이어서 이렇게 채워지는 것을 확인할 수 있다
mov eax, [ebp-8]
=> add dword ptr [ebp-8],2
자동으로 올리디버거가 변환해준다
무한루프 jmp 코드
64비트 dbg
다운로드 : https://x64dbg.com/