반응형

악성코드 분석을 위한 리버스 엔지니어링 - 기본지식2



문법별 어셈블리어 이해

1.PUSH EBP
2.MOV EBP,ESP
3.Sub ESP,0C
4.MOV DWORD PTR:SS[ebp-4],2
5.MOV DWORD PTR:SS[ebp-8],4
6.MOV EAX,DWORD PTR SS:[ebp-4]
7.ADD EAX,DWORD PTR SS:[ebp-8]
8.MOV DWORD PTR SS:[ebp-c],EAX
9.MOV ECX,DWORD PTR SS:[ebp-C]
10.PUSH ECX
11.PUSH basic.002E20EC
12.CALL DWORD PTR DS:[<&MSVCR100.printf>]
13.ADD ESP,8
14.XOR Eax,EAX
15.MOV ESP,EBP
16.POP EBP

17.RETN

각 라인 별 해석 // 실제 컴파일시 위와 같이 안나올 가능성이 매우 높음

1 ~ 2 : 함수 프롤로그
3 : 12만큼 공간 할당
4 : ebp-4에 2를 저장
5 : ebp-8에 4를 저장
6 : EAX레지스터에 ebp-4의 값인 2를 이동
7 : EAX레지스터와 ebp-8의 값인 4를 합쳐서 EAX에 저장
8 : EAX값을 ebp-c에 저장
9 : ebp-c의 값을 ECX에 저장
10 : ECX를 스택에 저장
11 : printf의 인자값으로 basic.002E20EC값을 스택에 저장
12 : CALL 명령어로 Printf 함수를 호출
13 : 시작주소에 8을 더해 변수 공간 해제
14 : EAX값을 0으로 초기화
15 ~ 16 : 함수 에필로그
17 : 종료



1.PUSH EBP
2.MOV EBP,ESP
3.PUSH ECX
4.MOV DWORD PTR SS:[EBP-4],0A
5.CMP DWORD PTR SS:[EBP-4],0A
6.JGE SHORT IF.00EE1021
7.PUSH IF.00EE20EC
8.CALL DWORD PTR DS:[<&MSVCR100.printf>]
9.ADD ESP,4
10.JMP SHORT if.00EE1045
11.CMP DWORD PTR SS:[EBP-4],0A
12.JNZ SHORT IF.00EE1037
13.PUSH IF.00EE20F4
14.CALL DWORD PTR DS:[<&MSVCR100.printf>]
15.ADD ESP,4
16.JMP SHORT IF.00EE1045
17.PUSH IF.00EE2100
18.CALL DWORD PTR DS:[&MSVCR100.printf>]
19.ADD ESP,4
20.XOR EAX, EAX
21.MOV ESP,EBP
22.POP EBP
23.RETN


1 ~ 2 : 함수 프롤로그
3 : 스택에 ECX값 저장
4 : 0A(10)을 EBP-4에 이동
5 : 0A(10)과 ebp-4의 값과 " - " 연산 진행
6 : 크거나 같다면 IF.00EE1021로 점프
7 : 메모리 공간을 할당하고 인자 값을 저장함
8 : call로 printf를 호출
9 : ESP에 4를 더함
10 : IF.00EE1045로 점프
11 : ebp-4 와 0A를 " - " 연산을 진행
12 : 0이 아니면 IF.00EE1037로 점프
13 : If.00Ee20F4의 값을 저장
14 : printf 호출
15 : esp에 4를 더함
16 : IF.00EE1045로 점프
17 : IF.00EE2100를 저장
18 : printf 호출
19 : esp에 4를 저장
20 : EAX를 초기화
21 ~ 22 : 함수 에필로그
23 : 끝





1.PUSH EBP
2.MOV EBP,ESP
3.PUSH ECX
4.MOV DWORD PTR SS:[ebp-4],0
5.CMP DWORD PTR SS:[ebp-4],5
6.JGE SHORT while.00e1102E
7.MOV EAX, DWORD PTR SS:[ebp-4]
8.PUSH EAX
9.PUSH while.00E120EC
10.CALL DWORD PTR DS:[<&MSVCR100.printf>]
11.ADD ESP,8
12.MOV ECX, DWORD PTR SS:[ebp-4]
13.ADD ECX,1
14.Mov DWORD PTR SS:[ebp-4],ECX
15.JMP SHORT while.00E1100B
16.XOR EAX,EAX
17.MOV ESP,EBP
18.POP EBP
19.RETN


1 ~ 2 : 함수 프롤로그
3 : 스택 프레임에 ECX값 저장
4 : ebp-4에 0을 이동
5 : ebp-4의 값과 5를 비교
6 : 크거나 같으면 while.00E1102E로 점프
7 : ebp-4의 값을 eax에 이동
8 : eax를 스택프레임에 저장
9 : while.00e120ec를 스택 프레임에 저장
10 : printf 함수 호출
11 : ESP에 8 더하기
12 : ebp-4의 값을 ecx에 이동
13 : ecx에 1 더하기
14 : ecx의 값을 ebp-4로 이동
15 : while.00E1100B로 점프    //5 ~ 15반복하며 값 증가 시킴 만족할 때 까지
16 : EAX 초기화
17 ~ 18 : 함수 에필로그
19 : 끝


함수 호출 규약의 종류

stdcall
stdcall 로 함수가 규약이 되어 있으면, 함수를 호출한 쪽에서 parameter 값들을 함수가 return 되고 난후 stack 에서 제거합니다. 따라서 호출한 함수가 자신의 parameter 를 알고 있기 때문에 printf 와 같이 parameter 가 가변적인 함수에서 사용가능합니다. 

cdecl
이 규약은 함수를 호출 받은 쪽(즉 함수의 내부)에서 parameter 를 제거하도록 되어 있습니다. 따라서 parameter 의 갯수가 명확한 곳에서 사용하게 되어 있죠. 윈도우즈의 API 와 같은 경우 함수에 따른 인자들이 명확히 정의 되어 있기 때문에 바로 __cdecl 규약을 사용하고 있습니다. 

fastcall
__fastcall은 인수 전달을 위해 edx, ecx 레지스터를 사용하는데 두 개의 인수를 차례대로 edx, ecx에 대입했다. 만약 인수가 둘 이상이면 세 번째 이후의 인수는 __cdecl과 마찬가지로 스택에 밀어넣을 것이다. 인수 전달을 위해 스택을 쓰지 않고 레지스터를 우선적으로 사용하므로 인수 전달 속도가 빠르다는 이점이 있다. 함수의 코드는 다음처럼 작성된다.

자세한 내용은 아래의 블로그 참조


stdcall

1.PUSH EBP

2.MOV EBP,ESP
3.PUSH 2
4.PUSH 1
5.CALL stdcall.strcall_test
6.XOR EAX,EAX
7.POP EBP
8.RETN
9.PUSH EBP
10.MOV EBP,ESP
11.PUSh ECX
12.MOV DWORD PTR:SS[ebp-4],0
13.MOV EAX,DWORD PTR:SS[epb+8]
14.ADD EAX,DWORD PTR:SS[ebp+c]
15.MOV DWORD PTR SS:[ebp-4],EAX
16.MOV EAX,DWORD PTR SS:[ebp-4]
17.MOV ESP,EBP
18.POP EBP
19.RETN 8


1 ~ 2 : 함수 에필로그
3 : 2값을 저장
4 : 1값을 저장
5 : stdcall로 strcall_test함수 호출
6 : EAX값 초기화
7 : EBP의 값 꺼내기
8 : 끝
9 ~ 10 : 함수 에필로그
11 : ECX값을 스택 프레임에 저장
12 : ebp-4에 0을 이동
13 : eax에 ebp+8의 값 이동
14 : eax에 ebp+c의 값을 추가
15 : ebp-4에 eax값 이동
16 : eax에 ebp-4값 저장
17 ~ 18 : 함수 에필로그
19 : call로 복귀




반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기