2012. 3. 21. 02:44
=====================================================================
gdb 분석법에 대한 복습!

envirment :
Linux server1 2.6.28-18-server #59-Ubuntu SMP Thu Jan 28 02:23:52 UTC 2010 i686 GNU/Linux



코드는 몽형이 짠걸 얼추 기억해서 ... 재코딩

#include<stdio.h>
#include<string.h>

int main(int argc, char *argv[]){

char buff[40];


if(argc!=7){
printf("failed\n");
}

else{
fgets(buff,"17",stdin);

printf("%s",buff);

if(strstr("key",buff)==0){

printf("success\n");
}

else{
printf("failed\n");
}
}

}
#########################################################################
분석을 마치며 느낀점

ubuntu 는 프로시져 프롤로그 부분이 다르다. 스택을 좀더 보호하는 쪽인것 같은데
정확히 파악을 하지 못했다.

또한 print 함수를 호출하는 대신 같은 printf 라도 puts 를 통해 글자를 출력한다.

마지막으로 인자값전달에서 스택에 push하고 빼는 형식의 redhat 과는 달리

(%esp), 0x4(%esp), 0x8(%esp) 같은 식으로 esp 부분에 인자값을 하나식 전달하는 방법을
사용함을 알수 있었다.

마지막으로 16바이트로 주소값 끝에 00을 맞춰주려던 sub 함수들도 사라져 있는것을 알수 있다.
#########################################################################
=====================================================================

#### gdb 명령어 실행 ######

study@server1:~/programming/hack/gdb_excercise$ gdb -q argv
(gdb) disass main
Dump of assembler code for function main:
0x080484a4 <main+0>: lea 0x4(%esp),%ecx
0x080484a8 <main+4>: and $0xfffffff0,%esp
0x080484ab <main+7>: pushl -0x4(%ecx)
0x080484ae <main+10>: push %ebp
0x080484af <main+11>: mov %esp,%ebp
0x080484b1 <main+13>: push %ecx
0x080484b2 <main+14>: sub $0x44,%esp
0x080484b5 <main+17>: mov 0x4(%ecx),%eax
0x080484b8 <main+20>: mov %eax,-0x38(%ebp)
0x080484bb <main+23>: mov %gs:0x14,%eax
0x080484c1 <main+29>: mov %eax,-0x8(%ebp)
0x080484c4 <main+32>: xor %eax,%eax
0x080484c6 <main+34>: cmpl $0x7,(%ecx)
0x080484c9 <main+37>: je 0x80484d9 <main+53>
0x080484cb <main+39>: movl $0x8048610,(%esp)
0x080484d2 <main+46>: call 0x80483e0 <puts@plt>
0x080484d7 <main+51>: jmp 0x8048527 <main+131>
0x080484d9 <main+53>: mov 0x804a020,%eax
0x080484de <main+58>: mov $0x8048617,%edx
0x080484e3 <main+63>: mov %eax,0x8(%esp)
0x080484e7 <main+67>: mov %edx,0x4(%esp)
0x080484eb <main+71>: lea -0x30(%ebp),%eax
0x080484ee <main+74>: mov %eax,(%esp)
0x080484f1 <main+77>: call 0x80483a0 <fgets@plt>
0x080484f6 <main+82>: lea -0x30(%ebp),%eax
0x080484f9 <main+85>: mov %eax,0x4(%esp)
0x080484fd <main+89>: movl $0x8048619,(%esp)
0x08048504 <main+96>: call 0x80483c0 <strstr@plt>
0x08048509 <main+101>: test %eax,%eax
0x0804850b <main+103>: jne 0x804851b <main+119>
0x0804850d <main+105>: movl $0x804861d,(%esp)
0x08048514 <main+112>: call 0x80483e0 <puts@plt>
0x08048519 <main+117>: jmp 0x8048527 <main+131>
0x0804851b <main+119>: movl $0x8048610,(%esp)
0x08048522 <main+126>: call 0x80483e0 <puts@plt>
0x08048527 <main+131>: mov -0x8(%ebp),%edx
0x0804852a <main+134>: xor %gs:0x14,%edx
0x08048531 <main+141>: je 0x8048538 <main+148>
0x08048533 <main+143>: call 0x80483d0 <__stack_chk_fail@plt>
0x08048538 <main+148>: add $0x44,%esp
0x0804853b <main+151>: pop %ecx
---Type <return> to continue, or q <return> to quit---
0x0804853c <main+152>: pop %ebp
0x0804853d <main+153>: lea -0x4(%ecx),%esp
0x08048540 <main+156>: ret


###################################################################

break main 으로 *를 사용하지 않아서 프롤로그 부분을 넘긴다.
=> gdb 가 버리가 좋아서 main 함수에 break 를 잡으면 아라서 프롤로그를 넘긴다.

###################################################################
(gdb) break main
Breakpoint 1 at 0x80484b2
0x080484b2 <main+14>: 같은 주소값이 main+14 이니깐 이 이후가 실제 코드영역이다.

0x080484a4 <main+0>: lea 0x4(%esp),%ecx
0x080484a8 <main+4>: and $0xfffffff0,%esp
0x080484ab <main+7>: pushl -0x4(%ecx)
0x080484ae <main+10>: push %ebp
0x080484af <main+11>: mov %esp,%ebp
0x080484b1 <main+13>: push %ecx
이부분은 esp를 ebp 에 넣고 스택을 완성하며 ecx를 넣어서 스택 가드를 형성한다.
이때 ebp 를 push 하고 스택 포인터를 ebp 에 넣은다음 ecx를 push 한다.

즉,
[buff][ ecx ][sfp][ret][argc][argv]
(스택가드와 연관있을듯)가 되어있다.


0x080484b2 <main+14>: sub $0x44,%esp //스택을 68바이트만큼 확장
0x080484b5 <main+17>: mov 0x4(%ecx),%eax //ret 주소를 eax 에 저장
0x080484b8 <main+20>: mov %eax,-0x38(%ebp) //ret주소가 저장된 eax를 확장된스택 56바이트 지점에 삽입
0x080484bb <main+23>: mov %gs:0x14,%eax
0x080484c1 <main+29>: mov %eax,-0x8(%ebp)

스택을 44(16)바이트 만큼 확장 시킨다.
(gdb) print 0x44
$2 = 68(만큼 확장)

print 0x38=56

/////////////////////////////////////////////////////////////////////////////
먼말인지 모르겠다 ㅠ..ㅠ
////////////////////////////////////////////////////////////////////////////

0x080484c6 <main+34>: cmpl $0x7,(%ecx) //argc 가 7개인가 비교
0x080484c9 <main+37>: je 0x80484d9 <main+53> //같다면 main 53으로.
0x080484cb <main+39>: movl $0x8048610,(%esp) //아니라면 failed 를 esp 에삽입
0x080484d2 <main+46>: call 0x80483e0 <puts@plt> //printf 대신 puts로 이동한다?
0x080484d7 <main+51>: jmp 0x8048527 <main+131> //마지막으로 이동하여 에필로그.
0x080484d9 <main+53>: mov 0x804a020,%eax //인자값이 7일때 stdin 을 eax에 저장
0x080484de <main+58>: mov $0x8048617,%edx //3이란 숫자를 edx에 받고.
0x080484e3 <main+63>: mov %eax,0x8(%esp) //esp 8만큼 떨어진곳에 그값을저장
0x080484e7 <main+67>: mov %edx,0x4(%esp) //4만틈 떨어진곳에 edx를 저장.
0x080484eb <main+71>: lea -0x30(%ebp),%eax //48만큼 떨어진 ebp 값을(입력받은 버퍼값) eax 에 복사
0x080484ee <main+74>: mov %eax,(%esp) //입력버퍼값을 마지막 인자로 전달.
0x080484f1 <main+77>: call 0x80483a0 <fgets@plt> //fget를 호출.(입력받는다)


(gdb) x/s 0x8048610
0x8048610: "failed"
Breakpoint 1, 0x080484d2 in main ()
(gdb) ni
failed
0x080484d7 in main ()
(gdb)

(gdb)
===================================================================
reghat 과 다르게 puts로 이동한다?
기억상으론 printf 부분이여야 한다.
puts 분석은 맨 아래로..

===================================================================
(gdb) x/s 0x804a020
0x804a020 <stdin@@GLIBC_2.0>: " Tú·"
(gdb)


(gdb) x/s 0x8048617
0x8048617: "3"
(gdb)
(gdb) print 0x30
$3 = 48
(gdb)
(gdb)

========================================================================

0x080484f6 <main+82>: lea -0x30(%ebp),%eax //입력받은 값을 eax로 전달.
0x080484f9 <main+85>: mov %eax,0x4(%esp) //그값을 esp 두번째 인자로 저장.
0x080484fd <main+89>: movl $0x8048619,(%esp) //key 라는 값을 첫번째 인자로 전달
0x08048504 <main+96>: call 0x80483c0 <strstr@plt> //strstr 함수 호출
0x08048509 <main+101>: test %eax,%eax
0x0804850b <main+103>: jne 0x804851b <main+119> //같지 않다면 119로 이동.
0x0804850d <main+105>: movl $0x804861d,(%esp) //sucsess 를 첫번째 인자로전달
0x08048514 <main+112>: call 0x80483e0 <puts@plt> //puts 호출
0x08048519 <main+117>: jmp 0x8048527 <main+131> //131로 이동하여 에필로그수행
0x0804851b <main+119>: movl $0x8048610,(%esp) //failed 저장
0x08048522 <main+126>: call 0x80483e0 <puts@plt> //puts 호출
0x08048527 <main+131>: mov -0x8(%ebp),%edx

=======================================================================
(gdb) x/s 0x8048619
0x8048619: "key"

(gdb) x/s 0x804861d
0x804861d: "success"
(gdb)
(gdb) x/s 0x8048610
0x8048610: "failed"
(gdb)


(gdb)



==================================================================================
else 용어 정리

실행법.
시작과 중단
kill : 중단
run : 시작

Assembly 문법 변경
set disassembly-flavor [intel | att]

약어 : set di i
set di a

도움말 : help

[주요 명령어]
disass
break
clear delete (clear는 주소/심볼 delete 는 bp number 로 가능)
info break 브레이크 포인트 리스트 보기
continue : 실행 재개
Stepi:step instruction 함수를 만나면안으로 따라 들어감, 약어 : si
Nexti : next instruction 함수를 만나면 그냥 실행시킴 약어 : ni

info reg : cpu regster 출력. (올리디버거 효과)

[ break 심화 ]
rbreak ^foo 함수 전체 브레이크 포인트
hbreak [same] : hardware break point
tbreak [same] : temp break point
condition [break_number]i==100 조건 브레이크

데이터보기
print/F [대상] : 값 출력
x/CSF [대상] : 주소 + 값 출력
c(count)::1~xxx
s(size) : b(byte),h(half word), w(word), g(giant==8byte)
f(formet): c(char),s(string),x(hex),a(address),i(instruction),t(binary)
whatch [대상]
데이터값이 변경될 때마다 알려줌

데이터 변경하기

P [symbol] =값
set *[Address]=값
set $[Register]=값
실행 흐름 변경하기
Set $eip = xxx


Core파일 분석하기

gdb - c core : gdb 실행시 로딩
core-file ./ore : gdb 실행후 로딩
gdb ./xxx -c core : 심볼과 함께 로딩
bt: back tracing
stack frame
ulmit -c [size_kb]
코어파일 생성하도록 설정 변경

[기타 팁들 ]
실시간 명령 보기
display/10i $eip : 실시간 명령설정
undisplay : 설정 취소

바이너리내 심볼보기
info variables )모든 변수), info locals(지역변수), info functions(모든 함수)
사용자 명령정의
define abc(끝날땐 end)

gdb 설정파일
~/.gdbinit 파일 생성
Print 를 계산기로 활용가능
Print 10+20
print/c 0xbffffffd8 = 음수 측정

부모함수로 빠져나가기 up
Posted by k1rha