reversing/리버싱 코드 복원
03.Control_Statements_Quiz_07
grinidia
2025. 4. 22. 20:10
문제
문제 풀이
07_Quiz.exe 를 OllyDBG에서 확인하면 아래와 같다.
00401000 /$ 55 PUSH EBP
00401001 |. 8BEC MOV EBP, ESP
00401003 |. 83EC 10 SUB ESP, 10
00401006 |. 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
00401008 |. 68 30504000 PUSH 03_07_Qu.00405030 ; |Title = "ITBANK"
0040100D |. 68 38504000 PUSH 03_07_Qu.00405038 ; |Text = "Insert Argument"
00401012 |. 6A 00 PUSH 0 ; |hOwner = NULL
00401014 |. FF15 94404000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>] ; \MessageBoxA
0040101A |. C745 F4 0000000>MOV DWORD PTR SS:[EBP-C], 0
// EBP-C 에 0을 할당
// for 문 진입
00401021 |. EB 09 JMP SHORT 03_07_Qu.0040102C
00401023 |> 8B45 F4 /MOV EAX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
00401026 |. 83C0 01 |ADD EAX, 1
00401029 |. 8945 F4 |MOV DWORD PTR SS:[EBP-C], EAX
0040102C |> 8B4D 10 MOV ECX, DWORD PTR SS:[EBP+10]
0040102F |. 034D F4 |ADD ECX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
00401032 |. 0FBE11 |MOVSX EDX, BYTE PTR DS:[ECX]
00401035 |. 85D2 |TEST EDX, EDX ; ntdll.KiFastSystemCallRet
00401037 |. 74 02 |JE SHORT 03_07_Qu.0040103B
00401039 |.^ EB E8 \JMP SHORT 03_07_Qu.00401023
// _n1+1을 함수에 매개변수로 사용하는 로직
0040103B |> 8B45 F4 MOV EAX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
0040103E |. 83C0 01 ADD EAX, 1
00401041 |. 50 PUSH EAX
00401042 |. E8 9D010000 CALL 03_07_Qu.004011E4
00401047 |. 83C4 04 ADD ESP, 4
// PUSH 한 EAX, 1 없앤다.
0040104A |. 8945 F0 MOV DWORD PTR SS:[EBP-10], EAX
// malloc 함수 결과 값 [EBP-10] 저장 (반환 값이 PTR이므로 포인터 주소 값을 반환으로 유추가능)
0040104D |. 8B4D F0 MOV ECX, DWORD PTR SS:[EBP-10]
00401050 |. 894D FC MOV DWORD PTR SS:[EBP-4], ECX
// [EBP-10]를 [EBP-4] 포인터 변수에 다시 할당한다.
00401053 |. C745 F4 0000000>MOV DWORD PTR SS:[EBP-C], 0
// 기존의 [EBP-4]에 0을 할당한다.
// While 문 진입
0040105A |> 8B55 10 /MOV EDX, DWORD PTR SS:[EBP+10]
0040105D |. 0355 F4 |ADD EDX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
00401060 |. 0FBE02 |MOVSX EAX, BYTE PTR DS:[EDX]
00401063 |. 85C0 |TEST EAX, EAX
00401065 |. 0F84 BB000000 |JE 03_07_Qu.00401126
// 0인지 확인하는 로직
// 첫 번째 분기 (if)
0040106B |. 8B4D 10 |MOV ECX, DWORD PTR SS:[EBP+10]
0040106E |. 034D F4 |ADD ECX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
00401071 |. 0FBE11 |MOVSX EDX, BYTE PTR DS:[ECX]
00401074 |. 83FA 41 |CMP EDX, 41
00401077 |. 7C 14 |JL SHORT 03_07_Qu.0040108D
00401079 |. 8B45 10 |MOV EAX, DWORD PTR SS:[EBP+10]
0040107C |. 0345 F4 |ADD EAX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
0040107F |. 0FBE08 |MOVSX ECX, BYTE PTR DS:[EAX]
00401082 |. 83F9 5A |CMP ECX, 5A
00401085 |. 7F 06 |JG SHORT 03_07_Qu.0040108D
00401087 |. C645 F8 41 |MOV BYTE PTR SS:[EBP-8], 41
0040108B |. EB 63 |JMP SHORT 03_07_Qu.004010F0
// 두 번째 분기 (else if)
0040108D |> 8B55 10 |MOV EDX, DWORD PTR SS:[EBP+10]
00401090 |. 0355 F4 |ADD EDX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
00401093 |. 0FBE02 |MOVSX EAX, BYTE PTR DS:[EDX]
00401096 |. 83F8 61 |CMP EAX, 61
00401099 |. 7C 14 |JL SHORT 03_07_Qu.004010AF
0040109B |. 8B4D 10 |MOV ECX, DWORD PTR SS:[EBP+10]
0040109E |. 034D F4 |ADD ECX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
004010A1 |. 0FBE11 |MOVSX EDX, BYTE PTR DS:[ECX]
004010A4 |. 83FA 7A |CMP EDX, 7A
004010A7 |. 7F 06 |JG SHORT 03_07_Qu.004010AF
004010A9 |. C645 F8 61 |MOV BYTE PTR SS:[EBP-8], 61
004010AD |. EB 41 |JMP SHORT 03_07_Qu.004010F0
// 세 번째 분기 (else if)
004010AF |> 8B45 10 |MOV EAX, DWORD PTR SS:[EBP+10]
004010B2 |. 0345 F4 |ADD EAX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
004010B5 |. 0FBE08 |MOVSX ECX, BYTE PTR DS:[EAX]
004010B8 |. 83F9 20 |CMP ECX, 20
004010BB |. 75 1B |JNZ SHORT 03_07_Qu.004010D8
004010BD |. 8B55 FC |MOV EDX, DWORD PTR SS:[EBP-4]
004010C0 |. 0355 F4 |ADD EDX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
004010C3 |. 8B45 10 |MOV EAX, DWORD PTR SS:[EBP+10]
004010C6 |. 0345 F4 |ADD EAX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
004010C9 |. 8A08 |MOV CL, BYTE PTR DS:[EAX]
004010CB |. 880A |MOV BYTE PTR DS:[EDX], CL
004010CD |. 8B55 F4 |MOV EDX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
004010D0 |. 83C2 01 |ADD EDX, 1
004010D3 |. 8955 F4 |MOV DWORD PTR SS:[EBP-C], EDX ; ntdll.KiFastSystemCallRet
004010D6 |.^ EB 82 |JMP SHORT 03_07_Qu.0040105A
// 조건분기를 완료했는데 반복문의 처음으로 돌아간다.
// 이를 보고 continue; 를 유추할 수 있다.
004010D8 |> 6A 00 |PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004010DA |. 68 48504000 |PUSH 03_07_Qu.00405048 ; |Title = "ITBANK"
004010DF |. 68 50504000 |PUSH 03_07_Qu.00405050 ; |Text = "Insert An Alphabet"
004010E4 |. 6A 00 |PUSH 0 ; |hOwner = NULL
004010E6 |. FF15 94404000 |CALL DWORD PTR DS:[<&USER32.MessageBoxA>] ; \MessageBoxA
004010EC |. 33C0 |XOR EAX, EAX
004010EE |. EB 69 |JMP SHORT 03_07_Qu.00401159
// while 문 종료
004010F0 |> 8B45 10 |MOV EAX, DWORD PTR SS:[EBP+10]
004010F3 |. 0345 F4 |ADD EAX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
004010F6 |. 0FBE00 |MOVSX EAX, BYTE PTR DS:[EAX]
004010F9 |. 0FBE4D F8 |MOVSX ECX, BYTE PTR SS:[EBP-8]
004010FD |. 2BC1 |SUB EAX, ECX
004010FF |. 83C0 03 |ADD EAX, 3
00401102 |. 99 |CDQ
// 부호있을 나눗셈을 준비한다.
00401103 |. B9 1A000000 |MOV ECX, 1A
00401108 |. F7F9 |IDIV ECX
// EAX에 ECX를 나눈다.
0040110A |. 0FBE45 F8 |MOVSX EAX, BYTE PTR SS:[EBP-8]
0040110E |. 03D0 |ADD EDX, EAX
// n4를 더한다
00401110 |. 8B4D FC |MOV ECX, DWORD PTR SS:[EBP-4]
00401113 |. 034D F4 |ADD ECX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
00401116 |. 8811 |MOV BYTE PTR DS:[ECX], DL
00401118 |. 8B55 F4 |MOV EDX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
0040111B |. 83C2 01 |ADD EDX, 1
0040111E |. 8955 F4 |MOV DWORD PTR SS:[EBP-C], EDX ; ntdll.KiFastSystemCallRet
00401121 |.^ E9 34FFFFFF \JMP 03_07_Qu.0040105A
// while 문 종료
00401126 |> 8B45 FC MOV EAX, DWORD PTR SS:[EBP-4]
00401129 |. 0345 F4 ADD EAX, DWORD PTR SS:[EBP-C] ; kernel32.7C8399F3
0040112C |. C600 00 MOV BYTE PTR DS:[EAX], 0
0040112F |. 68 64504000 PUSH 03_07_Qu.00405064 ; ASCII "LWedqn"
00401134 |. 8B4D FC MOV ECX, DWORD PTR SS:[EBP-4]
00401137 |. 51 PUSH ECX
00401138 |. E8 23000000 CALL 03_07_Qu.00401160
// strcmp 함수 호출
0040113D |. 83C4 08 ADD ESP, 8
// [EBP-4] [EBP-C] 둘다 없앤다
00401140 |. 85C0 TEST EAX, EAX
00401142 |. 75 13 JNZ SHORT 03_07_Qu.00401157
// strcmp가 0인지 확인한다.
00401144 |. 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
00401146 |. 68 6C504000 PUSH 03_07_Qu.0040506C ; |Title = "ITBANK"
0040114B |. 8B55 10 MOV EDX, DWORD PTR SS:[EBP+10] ; |
0040114E |. 52 PUSH EDX ; |Text = "횒\xA4$"
0040114F |. 6A 00 PUSH 0 ; |hOwner = NULL
00401151 |. FF15 94404000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>] ; \MessageBoxA
00401157 |> 33C0 XOR EAX, EAX
00401159 |> 8BE5 MOV ESP, EBP
0040115B |. 5D POP EBP ; kernel32.7C816D4F
0040115C \. C2 1000 RETN 10
C 코드로 작성하면 아래와 같다.
#include <windows.h>
#include <stdlib.h>
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MessageBox(NULL, "Insert Argument", "ITBANK", MB_OK);
int _n1;
for(_n1=0; lpCmdLine[_n1] !=0; _n1++);
char *_n2 = (char *)malloc(_n1+1);
char *n3 = _n2;
char n4;
_n1 = 0;
while(lpCmdLine[_n1])
{
if (lpCmdLine[_n1] >= 'A' && lpCmdLine[_n1] <= 'Z')
{
n4 = 'A';
}
else if (lpCmdLine[_n1] >= 'a' && lpCmdLine[_n1] <= 'z')
{
n4 = 'a';
}
else if(lpCmdLine[_n1] == ' ')
{
n3[_n1] = lpCmdLine[_n1];
_n1++;
continue;
}
else
{
MessageBox(NULL, "Insert An Alphabet", "ITBANK", MB_OK);
return 0;
}
n3[_n1] = (lpCmdLine[_n1] - n4 + 3) % 26 + n4;
_n1 = _n1 + 1;
}
n3[_n1] = 0x00;
if(strcmp(n3, "LWedqn") == 0)
{
MessageBox(NULL, lpCmdLine, "ITBANK", MB_OK);
}
return 0;
}