2017. 7. 28. 16:05ㆍ0x02 Reverse Engineer/0x02. Reversing.kr
Decrypt File (EXE)
By Pyutic
UPX 가볍게 UNPACKING` ~ `
Microsoft Visual C++ v.10
0044A775 68 ACC14400 push run_unpa.0044C1AC ; ASCII "Key : "
0044A77A FF15 B0C04400 call near dword ptr [<&MSVCR100.printf>] ; MSVCR100.printf
0044A780 83C4 04 add esp,0x4
0044A783 E8 7868FBFF call run_unpa.00401000
0044A788 68 70D34400 push run_unpa.0044D370 ; ASCII "ransomeware"
0044A78D 68 B4C14400 push run_unpa.0044C1B4 ; ASCII "%s"
0044A792 FF15 B8C04400 call near dword ptr [<&MSVCR100.scanf>] ; MSVCR100.scanf
0044A798 83C4 08 add esp,0x8
0044A79B C745 E8 70D3440>mov dword ptr [ebp-0x18],run_unpa.0044D370 ; ASCII "ransomeware" // 내가 입력한 값
0044A856 |> /8B55 FC /mov edx,[local.1]
0044A859 |. |52 |push edx ; /stream
0044A85A |. |FF15 C0C04400 |call near dword ptr [<&MSVCR100.feof>] ; \feof
0044A860 |. |83C4 04 |add esp,0x4 ; end of file 파라미터 1개
0044A863 |. |85C0 |test eax,eax ; patch 해야할까?
0044A865 |74 30 je short run_unpa.0044A897 ; 얘를 je로 패치
0044A867 |. |E8 9467FBFF |call run_unpa.00401000
0044A86C |. |8B45 FC |mov eax,[local.1]
0044A86F |. |50 |push eax ; /stream
0044A870 |. |FF15 B4C04400 |call near dword ptr [<&MSVCR100.fgetc>] ; \getc
0044A876 |. |83C4 04 |add esp,0x4
0044A879 |. |8B4D F8 |mov ecx,[local.2]
0044A87C |. |8881 B8155400 |mov byte ptr [ecx+0x5415B8],al
0044A882 |. |E8 7967FBFF |call run_unpa.00401000
0044A8B4 /75 49 jnz short run_unpa.0044A8FF ; jne 로 패치
0044A8B6 |. |8B55 F8 |mov edx,[local.2]
0044A8B9 |. |0FBE8A B81554>|movsx ecx,byte ptr [edx+0x5415B8] ; 구글링해보니 파일 암호화
0044A8C0 |. |8B45 F8 |mov eax,[local.2]
0044A8C3 |. |33D2 |xor edx,edx
0044A8C5 |. |F775 F4 |div [local.3] ; 내가 입력한 키의 길이
0044A8C8 |. |0FBE92 70D344>|movsx edx,byte ptr [edx+0x44D370] ; 내가 입력한 키
0044A8CF |. |33CA |xor ecx,edx ; 0x31
0044A8D1 |. |8B45 F8 |mov eax,[local.2]
0044A8D4 |. |8888 B8155400 |mov byte ptr [eax+0x5415B8],cl ; eax+0x5415B8안에 31을 넣고
0044A8DA |. |E8 2167FBFF |call run_unpa.00401000 ; 쌩까고
0044A8DF |. |8B4D F8 |mov ecx,[local.2]
0044A8E2 |. |0FBE91 B81554>|movsx edx,byte ptr [ecx+0x5415B8]
0044A8E9 |. |81F2 FF000000 |xor edx,0xFF ; 0x31 ^ 0xff (0X31은 숫자 1)
0044A8EF |. |8B45 F8 |mov eax,[local.2]
0044A8F2 |. |8890 B8155400 |mov byte ptr [eax+0x5415B8],dl ; 결과가 31에서 CE로 바꼇다
0044A8F8 |. |E8 0367FBFF |call run_unpa.00401000
0044A8FD |.^|EB A6 \jmp short run_unpa.0044A8A5
내가 입력한 key : 123(0x31,0x32,0x33)
현재 찾은것은
key값 ^ 0xff = 0xCE
패치 한 바이너리
0044A8A5 |> /8B45 F8 /mov eax,[local.2] ; LOOP
0044A8A8 |. |83C0 01 |add eax,0x1
0044A8AB |. |8945 F8 |mov [local.2],eax
0044A8AE |> |8B4D F8 mov ecx,[local.2]
0044A8B1 |. |3B4D F0 |cmp ecx,[local.4]
0044A8B4 |. |75 49 |jnz short run_unpa.0044A8FF ; 패치해야하니?;;;;
0044A8B6 |. |8B55 F8 |mov edx,[local.2]
0044A8B9 |. |0FBE8A B81554>|movsx ecx,byte ptr [edx+0x5415B8]
0044A8C0 |. |8B45 F8 |mov eax,[local.2]
0044A8C3 |. |33D2 |xor edx,edx
0044A8C5 |. |F775 F4 |div [local.3]
0044A8C8 |. |0FBE92 70D344>|movsx edx,byte ptr [edx+0x44D370] ; 내가 입력한 key[i]
0044A8CF |. |33CA |xor ecx,edx ; key[i] ^ 0 = key[i]
0044A8D1 |. |8B45 F8 |mov eax,[local.2]
0044A8D4 |. |8888 B8155400 |mov byte ptr [eax+0x5415B8],cl ; [eax+0x5415B8]은 암호화 된 파일같다?
0044A8DA |. |E8 2167FBFF |call run_unpa.00401000
0044A8DF |. |8B4D F8 |mov ecx,[local.2]
0044A8E2 |. |0FBE91 B81554>|movsx edx,byte ptr [ecx+0x5415B8]
0044A8E9 |. |81F2 FF000000 |xor edx,0xFF ; key[i] ^ 0xff
0044A8EF |. |8B45 F8 |mov eax,[local.2]
0044A8F2 |. |8890 B8155400 |mov byte ptr [eax+0x5415B8],dl
0044A8F8 |. |E8 0367FBFF |call run_unpa.00401000
0044A8FD |.^\EB A6 \jmp short run_unpa.0044A8A5
재 패치한 바이너리
놉....재 패치하면 첨 부터 CMP ECX, [local.4] 에서 0 과 0이므로 점프됨...
그렇다면, 분석하면서 패치해야한다.(1라운드 돌고)
다시 바이너리 돌려서
내가 입력한 key : 123(0x31,0x32,0x33)
현재 찾은것은 (이 key값은 정답 key값이 아니므로 루틴만 이해하고 넘어가야 한다)
key값 ^ 0xff = 0xCE
key값 ^ 0xff = 0xCD
파일의 시그니처는 무엇일까..
1) EXE
2) PNG. JPG
3) DOCX
4) HWP 등등... 이 있을텐데 파일 복호화 니까
힌트에 Decrypt(EXE)라고 되어있었으니 2 3 4 다 재꾸자
EXE를 나타내는 설명 ?
54 68 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 6D 6F 64 65
이게 나오게 한번 짜볼까?
정상바이너리[i] ="54 68 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 6D 6F 64 65"
정상바이너리 OFFSET 4E ~ 73
정상바이너리[i]="0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,0x63,0x61,0x6E,0x6E,0x6F,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6E,0x20,0x69,0x6E,0x20,0x44,0x4F,0x53,0x20,0x6D,0x6F,0x64,0x65"
랜섬바이너리[i]= ?? 얼라 0바이트 ?????????? 아.... 암호못풀면 pe구조 다 깨지는구나...
ㅜㅜ 새로 바이너리 받아서 다시 했다.
이제 워게임 랜섬웨어랄지라도 VMWARE에서 하자
랜섬바이너리[i]= "C7 F2 E2 FF AF E3 EC E9 FB E5 FB E1 AC F0 FB E5 E2 E0 E7 BE E4 F9 B7 E8 F9 E2 B3 F3 E5 AC CB DC CD A6 F1 F8 FE E9"
랜섬바이너리[i]="0xC7,0xF2,0xE2,0xFF,0xAF,0xE3,0xEC,0xE9,0xFB,0xE5,0xFB,0xE1,0xAC,0xF0,0xFB,0xE5,0xE2,0xE0,0xE7,0xBE,0xE4,0xF9,0xB7,0xE8,0xF9,0xE2,0xB3,0xF3,0xE5,0xAC,0xCB,0xDC,0xCD,0xA6,0xF1,0xF8,0xFE,0xE9"
키 값의 길이는 ??? ???? ???? ??????
97 9A 8C 8C 93 9A
8B 8C 8F 93 9E 86 9C =?> 13자리
그렇다면 key[14] = {0x97 9A 8C 8C 93 9A 8B 8C 8F 93 9E 86 9C}; // 이 안에 진짜배기가 들어가야함
#include <stdio.h>
#include <string.h>
int main(void)
{
char binary_original[38] = {0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,0x63,0x61,0x6E,0x6E,0x6F,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6E,0x20,0x69,0x6E,0x20,0x44,0x4F,0x53,0x20,0x6D,0x6F,0x64,0x65};
char binary_ransome[38]={0xC7,0xF2,0xE2,0xFF,0xAF,0xE3,0xEC,0xE9,0xFB,0xE5,0xFB,0xE1,0xAC,0xF0,0xFB,0xE5,0xE2,0xE0,0xE7,0xBE,0xE4,0xF9,0xB7,0xE8,0xF9,0xE2,0xB3,0xF3,0xE5,0xAC,0xCB,0xDC,0xCD,0xA6,0xF1,0xF8,0xFE,0xE9};
// key value
// key strlen = 13
char decrypt_key[14]={0x97,0x9A,0x8C,0x8C,0x93,0x9A,0x8B,0x8C,0x8F,0x93,0x9E,0x86,0x9C};
char real_key[14]={"\0"};
// rule of game
// ransome[i] ^ ransome[i] ^ 0xff ^ key[i] => original[i]
// key를 구하려면
// original[i] ^ ransome[i] ^ 0xff
//printf("strlen = %d\n", sizeof(binary_ransome)/sizeof(binary_ransome[0]));
int i;
// C7이 54가 되어야 함. 그래야 올바른 EXE가 됨.
// 그렇다면, C7 ^ FF ^ ? = 54
// ? = C7 ^ FF ^ 54 가 됨
// 바이너리랜섬은 38개, 공개키(DECRYPT_KEY)는 14자리
// 공개키를 2번 반복하고 10번 더 써야하네?
// 키젠 문제랑 거의 흡사 ?
// ? = 6C
// l (엘)
// 하나만 더 해보자
/*
char binary_original[38] = {0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6F,0x67,0x72,0x61,0x6D,0x20,0x63,0x61,0x6E,0x6E,0x6F,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6E,0x20,0x69,0x6E,0x20,0x44,0x4F,0x53,0x20,0x6D,0x6F,0x64,0x65};
char binary_ransome[38]={0xC7,0xF2,0xE2,0xFF,0xAF,0xE3,0xEC,0xE9,0xFB,0xE5,0xFB,0xE1,0xAC,0xF0,0xFB,0xE5,0xE2,0xE0,0xE7,0xBE,0xE4,0xF9,0xB7,0xE8,0xF9,0xE2,0xB3,0xF3,0xE5,0xAC,0xCB,0xDC,0xCD,0xA6,0xF1,0xF8,0xFE,0xE9};
// key value
// key strlen = 13
char decrypt_key[14]={0x97,0x9A,0x8C,0x8C,0x93,0x9A,0x8B,0x8C,0x8F,0x93,0x9E,0x86,0x9C}; // 확실한 키가 아니므로 스킵
*/
// ? = F2 ^ FF ^ 68 = 65
// ? = e
// real rule = binary_ransome[i] ^ 0xff ^ binary_original[i] = key[i];
// 그럼 14개면 써먹으면 되네?
// 플래그 느낌이 온다.... le ... ^,^
printf("랜섬웨어 키 \n");
for(i=0; i<13; i++)
{
real_key[i] = binary_ransome[i] ^ 0xFF ^ binary_original[i];
printf("%c",real_key[i]);
}
}
'0x02 Reverse Engineer > 0x02. Reversing.kr' 카테고리의 다른 글
CRC1 (0) | 2018.01.05 |
---|---|
PEpasswd (0) | 2017.12.01 |
MusicPlayer (0) | 2017.07.28 |
EasyUnpackMe (0) | 2017.07.28 |
EasyKeygen (0) | 2017.07.28 |