본문 바로가기

Hacking&Security/Reversing

[Reversing] x64dbg 변수 추정, 간단한 코드분석

이번 포스팅은 아래 c언어로 작성된 소스코드를 토대로 만들어진 exe(실행 파일)을 x64dbg 분석 툴을 이용해서 분석하는 것을 목표로 합니다.

#include <stdio.h >
int main()
{

	int a, b, c, d;

	a = 22;
	b = 5;
	c = a + b;
	d = a - b;

	printf("a = %d\nb = %d\nc = %d\nd = %d", a, b, c, d);

}

 

주요 분석 부분의 메모리 주소는 다음과 같습니다.

메모리주소 어셈블리코드 주석(설명)
00401003 sub esp,10 변수가 4개
00401006 mov dword ptr ss:[ebp-4], 16 ebp-4     a=(22)
0040100D mov dword ptr ss:[ebp-8], 5 ebp-8     b=(5)
00401014 mov eax,dword ptr ss:[ebp-4] eax=(22)
00401017 add eax,dword ptr ss:[ebp-8] eax=(22) + (5)  = eax = (a) + (b)
0040101A mov dword ptr ss:[ebp-10], eax ebp-10=1B(27)       c=(a) + (b)
0040101D mov ecx, dword ptr ss:[ebp-4] ecx= (a)= 22
00401020 sub ecx, dword ptr ss:[ebp-8] ecx = (a) - (b)     (22)-(5)
00401023 mov dword ptr ss:[ebp-C], ecx ebp-C = (a) - (b)    11(17)
00401026 mov edx, dword ptr ss:[ebp-C] edx     d=(a) - (b) = (17)

한 줄 한 줄 살펴보겠습니다.

00401003 sub esp,10 변수가 4개

sub esp,10를 통해 소스코드에서 변수가 4개임을 유추할 수 있다고 설명란에 적었습니다.
일단 어셈블리 코드 란에서의 10은 16진수기 때문에 10진수로 변환하면 '16'이 된다는 점을 알아야 합니다.
16 진수 '10' -> 10진수 '16' 
sub는 빼기 명령어고, 'esp값에서 16을 뺀다'라는 의미입니다. 

esp를 16byte만큼 빼주며 스택 공간을 확보합니다. 함수의 로컬(지역) 변수는 스택에 저장되며, 선언할 변수는 int 타입이므로 4byte입니다. 즉, 4byte x 4개의 변수 ->16byte 로 추정할 수 있게 됩니다.

4byte의 변수 네 개를 스택에 저장해야 하기 때문에 16byte가 필요함으로 16byte의 공간을 빼서 네 개의 변수에게 필요한 메모리 공간을 확보해두는 의미입니다.

 

00401006 mov dword ptr ss:[ebp-4], 16 ebp-4     a=(22)

지역변수는 "ss:[주소]"로 표현하고,
전역변수는 "ds:[주소]"로 표현합니다.

mov는 목적지로 값을 넣을 때 사용합니다.
즉 해당 라인은 16진수의 '16'(10진수->'22')이라는 값을  [ebp-4]라는 주소에 저장하겠다는 의미입니다.
지역변수 a에 22라는 값을 저장하는 라인이라고 추정할 수 있습니다.

0040100D mov dword ptr ss:[ebp-8], 5 ebp-8     b=(5)

위와 같은 방식으로 예측했을 때 해당 라인은
16진수의 '5'(10진수 -> '5')라는 값을 [ebp-8]라는 주소에 저장하겠다는 의미입니다.
지역변수 b에 5라는 값을 저장하는 라인이라고 추정할 수 있습니다.

00401014 mov eax,dword ptr ss:[ebp-4] eax=(22)

위와 같은 형태는 mov eax,[esp] 형태인데, '주소[esp] 안의 값을 읽어와 eax에 저장함' 라고 설명할 수 있습니다. 
이와 같은 방식으로 예측했을 때 해당 라인은
주소 [ebp-4]에 저장된 값을 읽어와 eax에 저장한다는 의미입니다.

00401017 add eax,dword ptr ss:[ebp-8] eax=(22) + (5)  = eax = (a) + (b)

add는 산술연산 명령어입니다. 해당 라인은
저장된 eax에 주소 [ebp-8]에 저장된 값을 더한다는 의미입니다.
주소 [ebp-4]는 변수 a에 22라는 값을 저장했다고 추정했고, 이 값은 eax에 저장했습니다.
주소 [ebp-8]는 변수 b에 5라는 값을 저장하는 라인이라고 추정했으므로,
eax=(a) + (b)로 표현할 수 있습니다.
eax=(22) + (5)가 되네요.

0040101A mov dword ptr ss:[ebp-10], eax ebp-10=1B(27)       c=(a) + (b)

주소 [ebp-10]에 바로 위에서 표현한 eax의 값을 저장한다는 의미입니다.
ebp-10=1B(27)이 됩니다. 참고로 1B는 27의 16진수 변환자입니다.
동시에 변수들의 식으로 표현하면 c=(a) + (b)로 표현할 수 있습니다. 

0040101D mov ecx, dword ptr ss:[ebp-4] ecx= (a)= 22

ecx 안에 주소[ebp-4]의 저장된 값을 저장해줍니다.
ecx=(a)
ecx=22가 되는군요.

00401020 sub ecx, dword ptr ss:[ebp-8] ecx = (a) - (b)     (22)-(5)

ecx에서 주소 [ebp-8]에 저장된 값을 빼줍니다.
ecx에서는 변수a의 22가 저장되어 있었고, [ebp-8]에서는 변수 b의 5가 저장되어 있었으므로
22-5 = 17이 됩니다.

00401023 mov dword ptr ss:[ebp-C], ecx ebp-C = (a) - (b)     11(17)

[ebp-C]라는 주소에서 C는 10진수로 변환하면 12이므로 
ebp-C(12)라고 표현하면 편할 것 같습니다.
해당 주소에 (a)-(b)를 저장하는 것과 같으므로
주소 [ebp-C]에 저장된 값은 17이 될 것입니다.

변수 d=a-b로 표현할 수 있습니다.

00401026 mov edx, dword ptr ss:[ebp-C] edx     d=(a)-(b)=(17)

edx에 주소[ebp-C]에 저장된 값을 저장해줍니다.

 

이와 같이 코드를 분석하고 나면 c언어로 기반한 소스코드를 아래까지 유추할 수 있을 것입니다.

int a,b,c,d;

a=16;
b=5;
c= a+b;
d= a-b;

 

맨 처음 라인 00401003에서 sub esp,10 코드로 
esp를 16byte만큼 빼주며 스택 공간을 확보한다고 했습니다. 

오퍼랜드에 값을 저장했으니, push로 스택에 데이터를 밀어넣어줍니다.

출력함수를 불러옵니다. 해당 라인까지 [F8]로 실행하고 나면 아래 console창에서 실행 결과를 볼 수 있습니다.