프로그램: 올리디버거
실행파일: test.exe
test.exe를 분석한 첫 화면이다.
F8로 실행해 봤다.
다음과 같이 입력했다. serial에 123을 입력했다.
serial : 123
다음과 같은 주소가 Main함수인 것을 알 수 있다.
00401481 . E8 3AFCFFFF call test.004010C0 ; \test.004010C0
Main함수 부분에서 F7로 들어가 보겠다.
004010E1 |. 68 08E04000 push test.0040E008 ; ASCII "PassWord Crack "
004010E6 |. E8 A3010000 call test.0040128E
004010EB |. 83C4 04 add esp, 4
004010EE |. 68 18E04000 push test.0040E018 ; ASCII "serial : "
004010F3 |. E8 96010000 call test.0040128E
ASCII "PassWord Crack "와 ASCII "serial : "부분은 call로, F7 했을 때 들어갈 수 있다.
push는 스택에 추가한다. 스택에 추가된 PassWord Crack을 test.0040128E call 호출해서 프로그램에서 출력되게 만든다.
serial도 마찬가지로 스택에 추가해서 test.0040128E call 호출해 프로그램에서 출력되게 한다.
004010FE |. 52 push edx ; | Arg2
004010FF |. 68 24E04000 push test.0040E024 ; | Arg1 = 0040E024 ASCII "%s"
00401104 |. E8 68010000 call test.00401271 ; | test.00401271
%s를 보면 입력 값을 받는다는 것을 알 수 있다. 이 코드를 실행하면 입력을 받을 수 있다.
아까와 같이 123을 입력해 보겠다.
PassWord Crack
serial : 123
올리디버거에서는 그다음으로 넘어갔다.
0040110F |. 50 push eax ; /Arg1
00401110 |. E8 EBFEFFFF call test.00401000 ; \test.00401000
00401115 |. 83C4 04 add esp, 4
00401118 |. 8D4D E0 lea ecx, [local.8]
0040111B |. 51 push ecx ; /Arg2
0040111C |. 8D55 F4 lea edx, [local.3] ; | 0040111F |. 52 push edx ; |Arg1
00401120 |. E8 0BFFFFFF call test.00401030 ; \test.00401030
call로 연산하는 부분이다. test.00401000을 자세히 보면 "HackeRs"를 대문자로 바꿔서 "hACKErS"로 만드는 함수다. 주요 코드는 다음과 같다.
00401005 |> /8B45 08 /mov eax, [arg.1]
00401008 |. |83C0 01 |add eax, 1
0040100B |. |8945 08 |mov [arg.1], eax
0040100E |> |8B4D 08 mov ecx, [arg.1]
00401011 |. |0FBE11 |movsx edx, byte ptr ds:[ecx]
00401014 |. |85D2 |test edx, edx
00401016 |. |74 10 |je short test.00401028
00401018 |. |8B45 08 |mov eax, [arg.1] 0040101B |. |0FBE08 |movsx ecx, byte ptr ds:[eax]
0040101E |. |83F1 20 |xor ecx, 20
00401021 |. |8B55 08 |mov edx, [arg.1] 00401024 |. |880A |mov byte ptr ds:[edx], cl
00401026 |.^\EB DD \jmp short test.00401005
다음은 test.00401030을 보겠다.
00401039 |. E8 22010000 call test.00401160
이 것은 EAX에 00000007을 넣는다.
00401043 |. 8B4D 0C mov ecx, [arg.2]
ecx에 "123"을 넣는다.
Registers (FPU)
EAX 00000003
ESI 00000007
Code Windows 창(디스어셈블 보여주는 창)에서 eax는 3자리, esi는 7자리이기 때문에 서로 같지 않다.
0040104F |. 3BF0 cmp esi, eax
00401051 |. /74 07 je short test.0040105A <- z=0, jump하지 않음
00401053 |. |B8 01000000 mov eax, 1
00401058 |. |EB 53 jmp short test.004010AD <- 004010AD(비교구문 패스)로 점프
0040105A |> \C745 FC 00000>mov [local.1], 0
입력값: EAX
비교값: ESI
문자열의 크기를 cmp로 비교하는 듯하다.
je는 같을 때 jump 하는 어셈블리 코드다.
cmp로 비교해서 같지 않으니 je로 점프할 때 제로 플래그(ZF)가 0이 된다.
제로 플래그가 0이면 점프하지 않는다.
따라서 arg1과 arg2 문자열을 비교하는 부분을 jump한다.
1234567을 입력해 보겠다.
그 결과 cmp esi, eax와 je에서 Z 플래그가 1로 바뀐다.
0040104F |. 3BF0 cmp esi, eax
00401051 |. /74 07 je short test.0040105A
00401053 |. |B8 01000000 mov eax, 1
00401058 |. |EB 53 jmp short test.004010AD
0040105A |> \C745 FC 00000>mov [local.1], 0
z 플래그가 1이기 때문에 0040105A로 jump 한다.
z 플래그가 0이면 위와 같이 문자열 비교 부분 전체를 jmp(jump)해버린다.
0040108F |. 8B45 08 | mov eax, [arg.1] <- 비교 문자열
00401092 |. 0FBE08 | movsx ecx, byte ptr ds:[eax]
00401095 |. 8B55 0C | mov edx, [arg.2] <- 입력 값
00401098 |. 0FBE02 | movsx eax, byte ptr ds:[edx]
0040109B |. 83E8 01 | sub eax, 1
0040109E |. 3BC8 |cmp ecx, eax
004010A0 |. 74 07 | je short test.004010A9
004010A2 |. B8 01000000 |mov eax, 1
004010A7 |. EB 04 | jmp short test.004010AD
004010A9 |>^ EB B8 \ jmp short test.00401063
우선 비교 문자열에 들어간 값을 알아보자!
HackeRs: 처음 input 문자열
hACKErS: 대소문자 변환 문자열
대소문자 변환 문자열을 넣어보겠다.
hACKErS를 입력한 결과 실패했다.
다시 보니 sub eax, 1이라는 명령어가 눈에 띈다.
위의 대소문자 변환 call 함수에서와 같이 ASCII 코드를 하나씩 비교하는 것으로 추측된다.
먼저 -1을 한 eax가 비교 문자열인지 입력 문자열인지 확인해 보겠다.
eax가 68(h)에서 sub(-1)이 돼서 67(g)이 됐고, 따라서 같지 않다고 판단, jump 해버렸다.
때문에 모든 문자열 아스키코드에서 +1을 해주겠다.
번호 | 원래 문자 | 아스키 값 | 변환 문자 | 아스키 값 |
1 | h | 68 | i | 69 |
2 | A | 41 | B | 42 |
3 | C | 43 | D | 44 |
4 | K | 4b | L | 4D |
5 | E | 45 | F | 46 |
6 | r | 72 | s | 73 |
7 | S | 53 | T | 54 |
그 결과 다음과 같은 문자열이 나왔다.
iBDLFsT
그 결과 성공 문자가 출력됐다.
그런데 이상한 점이 있었다.
문자열 비교를 4개 문자인 iBDL만 한다는 것이다. 이는 뒤에 FsT 문자열은 무엇이 오든 상관이 없다는 말이 아닐까?
iBDLabc
다음 문자열을 입력해 봤다.
FsT를 abc로 바꿔서 상관이 있는지 확인해 보는 것이다.
성공했다.
상관이 없었다.
앞의 4개 문자만 비교한다는 것을 알 수 있었다.
느낀 점.
처음에는 main함수를 찾는 것조차 어려웠다.
그다음에는 비교하는 곳에서 뚫어져라 쳐다봐도 어셈블리어가 어떤 것을 의미하는지 한참을 쳐다봤다.
z플래그가 0이면 점프하지 않고, 1이면 점프한다는 것과 문자열에서 문자 하나씩 비교한다는 점, sub로 빼주어서 값이 같지 않았던 부분 등 어려운 점이 많았다.
이제 아스키코드가 조금. 아주아주 조금은 보이는 듯해서 기분이 좋다.