lyl -3부

2020. 4. 30. 20:280x02 Reverse Engineer/0x03. Etc

728x90

1부에서는 큰 틀을 잡았으며

2부에서는 큰 틀을 잡으면서 놓칠만한 것들을 꼼꼼히 살펴봤다.

이번 3부에서는 1부 2부를 총 정리하면서, 암호화 로직을 그대로 코딩해보자.


Enumeration

Dummy Value

Case 0 ~ A : Default Hardcode Data

[Unicode]

Case 음절

Case 어절

Logic

2바이트 (한글)을 입력받는다

프로그램 속 로직을 거친다.

라운드는 3라운드로 구성되어 있다.

 

암호화 로직은 이해하려고 노력하지 않았다. 개발자 마음이다.

 

1라운드 : 입력되어진 2바이트를 이용하여 암호화를 진행

한다. 종종 하드 코딩된 값을 연산에 사용하기도 한다.

모든 음절을 처리할 때까지 반복 수행한다.

 

 

2라운드 : 3라운드로 진입하기 위한 임시 변수를 만든다.

해당 임시 변수로 인해 케이스 별 출력문이 동작된다.

 

3라운드 : 2라운드에서 생성된 변수 값에 의해 데이터를 출력한다.

 

한글 한 글자만 입력하여 원본과 일치성을 대조해보았다.

컴파일 환경은 Windows 64bit Debugger 모드이며, 사용된 IDE는 Visual Studio 2017 Community이다.

코드 형태는 대략적으로 현 바이너리에 존재하는 OPCODE를 그대로 본 땄고, 일부 최적화하였다.

 

 

 

// rev_lyl.cpp: 콘솔 응용 프로그램의 진입점을 정의합니다.
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>

#define ERROR (0)
#define STDIN (0)
#define STDOUT (1)
#define STDERR (2)

#define _64BIT_INST (0xFFFFFFFF00000000)
#define INTRO(x) { printf("The current data is %d bytes\n",x); }
#define INFO(x)  { printf("There are (%d) bytes of temporary data available for encryption\n",x);}
#define PEDUMP(x) { printf("Dump => %s\n",argv[0]); }
#define S system("pause")
typedef unsigned long long ull;

const wchar_t *dummy0 = L"릴"; // B9B4
const wchar_t *dummy1 = L"릘"; // B998
const wchar_t *dummy2 = L"륄"; // B944 
const wchar_t *dummy3 = L"릴릘"; // B9B4 B998
const wchar_t *dummy4 = L"릘릘"; // B998 B998 릘릘
const wchar_t *dummy5 = L"릻륄"; // B9BB B944
const wchar_t *dummy6 = L"릴륄"; // B9B4 B944
const wchar_t *dummy7 = L"릘륄"; // B998 B944
const wchar_t *dummy8 = L"릘릴륄"; // %uB998%uB9B4%uB944
const wchar_t *dummy9 = L"릻릘륄"; // %uB998%uB998%uB944
const wchar_t *dummyA = L"릴릘륄";
const wchar_t *data = L"연"; // 휴

int main(int argc, char *argv[])

{
	ull tmp = 0x5400; // 0x5400은 최적화 결과 
					  //===========================
	ull RAX = 0x24924925; // 반복 시작 하는 구문 
	ull RBX = 0x00;
	ull RCX = 0x00;
	ull RDI = 0x00;
	ull RSI = 0x00;
	ull RDX = 0x00;
	ull RBP = 0x00;
	//===========================
	ull R8 = 0x00;
	ull R9 = 0x00;
	ull R12 = 0x00;
	ull R14 = 0x19;
	ull R15 = 0x00;
	ull FLAG = 0x00;

// 이 값이 유동적임 추후 수정 필요
	const char *dump =
		"\x07\x00\x00\x00\x17\x00\x00\x00\x0A\x00\x00\x00\x0A\x00\x00\x00"
		"\x01\x00\x00\x00\x8D\x02\x00\x00\x00\x00\xB8\x68\x8D\x02\x00\x00"
		"\xE0\x38\xB9\x68\x8D\x02\x00\x00\x6A\x00\x00\x40\x00\x00\x00\x00"
		"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
		"\x00\x54\x00\x00\x00\x00\x00\x00\xF0\x19\x00\x00\x00\x00\x00\x00"
		"\x00\x00\x00\x00\x00\x00\x00\x00\xF4\xED\x90\xFE\xC8\x00\x00\x00"
		"\x01\x00\x00\x00\x00\x00\x00\x00\x33\x18\xB5\x26\xF7\x7F\x00\x00"
		"\x00\x00\x00\x00\x00\x00\x00\x00\x50\xE9\x90\xFE\xC8\x00\x00\x00"
		"\xC2\xF5\x90\xFE\xC8\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
		"\x02\x00\x00\x00\x03\x00\x00\x00\x05\x00\x00\x00\x07\x00\x00\x00"
		"\x0B\x00\x00\x00\x0D\x00\x00\x00\x11\x00\x00\x00\x13\x00\x00\x00"
		"\x17\x00\x00\x00\x1D\x00\x00\x00\x1F\x00\x00\x00\x25\x00\x00\x00"
		"\x29\x00\x00\x00\x2B\x00\x00\x00\x2F\x00\x00\x00\x35\x00\x00\x00"
		"\x3B\x00\x00\x00\x3D\x00\x00\x00\x43\x00\x00\x00\x47\x00\x00\x00"
		"\x49\x00\x00\x00\x4F\x00\x00\x00\x53\x00\x00\x00\x59\x00\x00\x00"
		"\x61\x00\x00\x00\x65\x00\x00\x00\x67\x00\x00\x00\x6B\x00\x00\x00"
		"\x6D\x00\x00\x00\x71\x00\x00\x00\x7F\x00\x00\x00\x83\x00\x00\x00"
		"\x89\x00\x00\x00\x8B\x00\x00\x00\x95\x00\x00\x00\x97\x00\x00\x00"
		"\x9D\x00\x00\x00\xA3\x00\x00\x00\xA7\x00\x00\x00\xAD\x00\x00\x00"
		"\xB3\x00\x00\x00\xB5\x00\x00\x00\xBF\x00\x00\x00\xC1\x00\x00\x00"
		"\xC5\x00\x00\x00\xC7\x00\x00\x00\xD3\x00\x00\x00\xDF\x00\x00\x00"
		"\xE3\x00\x00\x00\xE5\x00\x00\x00\xE9\x00\x00\x00\xEF\x00\x00\x00"
		"\xF1\x00\x00\x00\xFB\x00\x00\x00\x01\x01\x00\x00\x07\x01\x00\x00"
		"\x0D\x01\x00\x00\x0F\x01\x00\x00\x15\x01\x00\x00\x19\x01\x00\x00"
		"\x1B\x01\x00\x00\x25\x01\x00\x00\x33\x01\x00\x00\x37\x01\x00\x00"
		"\x39\x01\x00\x00\x3D\x01\x00\x00\x4B\x01\x00\x00\x51\x01\x00\x00"
		"\x5B\x01\x00\x00\x5D\x01\x00\x00\x61\x01\x00\x00\x67\x01\x00\x00"
		"\x6F\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";

	// 연 일 때 첫 출력 case : 1 
	// 휴 일 때 첫 출력 case : 3 


	//wprintf(L"%d\n", wcslen(data));
	R15 = wcslen(data);
	INTRO(R15);

	wprintf(L"%s\n", data);
	S;
	/*
	wprintf(L"%X\n", data[0]);
	wprintf(L"%X\n", data[1]);
	*/
	//wprintf(L"%s\n", dummy0);
	wprintf(L"[+] REAL UNICODE VALUE %X\n", data[0]);
	if (!(wchar_t(data[0]) >= 0x21 && wchar_t(data[0]) <= 0x7E)) // 아스키 거부 의사 
	{
		// 최적화 
		/*
		00007FF | 0F B7 | movzx eax,word ptr ds:[rsi]              |
		00007FF | 66 83 | cmp ax,20                                | 20:' '
		00007FF | 75 07 | jne lyl language!.7FF7DE0716A5           |
		00007FF | 33 C9 | xor ecx,ecx                              |
		00007FF | E9 6B | jmp <lyl language!.round_1_escape>       |
		00007FF | 66 0F | movdqa xmm0,xmmword ptr ds:[7FF7DE075760 | 2
		00007FF | 48 8D | lea rcx,qword ptr ss:[rbp+44]            |
		00007FF | 66 0F | movdqa xmm1,xmmword ptr ds:[7FF7DE075860 | B
		00007FF | 66 41 | add ax,r13w                              | init
		*/

	__Routine_R1:
		tmp = (tmp + data[0]) & 0xFFFF;
		printf("[+] After optimization RAX =%lX\n", tmp); // 검산완료 
		printf("AX  = %llX\n", tmp & 0xFF);

		if ((tmp) == 0)
		{

		}

		//////////////////////////////////////////////////////////////

		// ELSE 
		R8 = 0x454;
		RAX = 0x24924925;
		R9 = RDI;
		RDI = tmp;
		RDX = RAX * tmp;
		printf("RDX = %llX\n", RDX); // 검산 완료 
									 //S;


		RAX = RDX & 0xFFFFFFFF;
		RDX = (RDX & _64BIT_INST) >> 32;

		// 00007FF | F7 E7 | mul edi                                  | 
		printf("RAX = %lX\n", RAX); //92492FB0
		printf("RDX = %llX\n", RDX); // 3B4
		printf("RDI = %llX\n", RDI); // 19F0

		R9 = RDI;
		printf("R9 = %llX\n", R9); // 19F0
								   //S;
		R9 -= RDX;
		printf("R9 = %llX\n", R9); // 

		R9 = (((tmp - RDX) >> 1) + RDX) >> 4;
		printf("R9 = %llX\n", R9); // ED

		RAX = R9 * 0x1C;
		printf("%RAX = %llX\n", RAX);

		R8 = tmp - RAX;
		printf("R8 = %llX\n", R8); // 0x4


								   // RAX Update
		RAX = 0xDEE95C4D;
		printf("RAX = %llX\n", RAX); //

		RDI = tmp;
		RDX = (RAX * tmp & _64BIT_INST) >> 32;
		RAX = (RAX * tmp) & 0xFFFFFFFF;
		printf("RAX = %llX\n", RAX); // 0xC4CA0D30
		printf("RDX = %llX\n", RDX); // 0x1695


		printf("RDI = %llX\n", RDI); // 0x19F0


									 // RAX Update
		RAX = 0x30C30C31;
		RDX = RDX >> 9;
		printf("RDX = %llX\n", RDX); // 0xB

		RCX = RDX;
		RAX *= R9; // imul r9d 
		RDX = (RAX & _64BIT_INST) >> 32;
		RAX &= 0xFFFFFFFF;

		printf("RAX = %llX\n", RAX); // 0x2492495D
		printf("RDX = %llX\n", RDX); // 0x2D

									 // RCX 0x25로 체인지
									 // 00007FF | 8B 4C | mov ecx,dword ptr ss:[rsp+rcx*4+20]      | 0x25
		RCX = 0x25;

		RDX >>= 2; // sar


		printf("RCX = %llX\n", RCX); // 0x25
		printf("RDX = %llX\n", RDX); // 0xB

		RAX <<= 0x1F; // shr eax,0x1F 편의상 0X00
					  //RAX = 0x00;

		RDX += RAX;
		//00007FF | 6B C2 | imul eax, edx, 15 |
		RAX = RDX * 0x15;
		RAX &= 0xFF;
		printf("RAX = %llX\n", RAX); // 0xE7

		R9 -= RAX;
		R9 &= 0xFF;
		printf("R9 =%llX\n", R9); // 0x
		
		RAX = R9;

		//00007FF | 0F AF | imul ecx,dword ptr ss:[rsp+rax*4+6C]     | 0x65
		RCX *= 0x65;

		printf("RCX = %llX\n", RCX); // 0xE99
		
		RAX = R8;

		//00007FF | 0F AF | imul ecx,dword ptr ss:[rbp+rax*4-40]     | 0xC5
		RCX *= 0xC5;
		printf("%llX\n", RCX); // 0xB3BBD
		printf("%llX\n", RAX); // 0x4
		
		R14 = RCX;

		printf("RCX = %llX\n", RCX); // 0xB3BBD
		R14 = RCX;
		//RSI += 2; // 흠 고민 
		R15 -= 1;
		INFO(R15);


		if (R15 != 0) // 연산 한번 더 
		{
			puts("**LOOP**");
			goto __Routine_R1;
		}

		// Round 2 
		puts("ROUND 2");
		
		RDX = RBX;
		printf("RAX = %llX\n", RAX);
		printf("RDX = %llX\n", RDX);
		
		//00007FF | 48 8D | lea rcx,qword ptr ss:[rbp+4A0]           |
		// RCX 값 변하지 않음 
		puts("Processing ROUND 2");
		
		RDX &= RDX;
		if (RDX == ERROR)
		{

		}
		R12 = RDX;
		R15 = RCX;
		R14 ^= R14;
		
		PEDUMP(argv[0]);
	__Routine_R3:
		RCX = R15;
		R15 &= R15; // using loop 
		printf("RCX = %llX\n", RCX); // B3BBD
		S;
		if (RCX == 0)
		{
			puts("늴"); // 0x7FF726B555D8 (%uB2B4)
		}


	
		RDI ^= RDI;
		R8 ^= R8;
		RBP ^= RBP;

	__Routine_R2:
		RAX = 0x4BDA12F7;
		printf("RAX = %llX\n", RAX);
		R8++; // lea r8, qword ptr ds:[r8+1] 
		printf("R8 = %llX\n", R8);
		printf("R9 = %llX\n", R9);
		
		RDX = ((RAX * RCX)& _64BIT_INST) >> 32;
		RAX = (RAX * RCX) & 0xFFFFFFFF;
		printf("RDX = %llX\n", RDX); // 0x35412
		printf("RAX = %llX\n", RAX); // 0x12FBED5B

		RDI++;
		RDX >>= 3;
		RAX >>= 0x1F; //  (shr eax, 0x1F)
		printf("RDX = %llX\n", RDX); // 0x6A82

									 // 이 부분 없어도 됨 noisy 코드 
		printf("RAX = %llX\n", RAX); // 0x354100000000(origin)

		RAX += RDX;
		RAX = RDX * 0x1B;
		printf("RAX = %llX\n", RAX); // 0xB3BB6
		RCX -= RAX;
		
		printf("RCX = %llX\n", RCX); // 0x7 
		
		RCX = RDX;
		RDX &= RDX; // tet edx, edx
		printf("** RDX = %llX\n", RDX);
		
		if (RDX != 0)
		{
			printf("LOOP\n");
			goto __Routine_R2;
		}
		// escape loop  
		// mov dword ptr ds:[r15], edx

		R15 = RDX; // 추가
		RDI &= RDI;
		if (RDI == 0)
		{
			if (R14 == R12)
			{
				R14++;
				R15 += 4;
			}
			else
			{
				puts("닐");
				R14++;
				R15 += 4;
				if (R14 == R12)
				{
					goto __Routine_R3;
				}
				// need to check
				/*else
				{

				}*/

			}
		}
		else
		{
			// lea rsi, qword ptr ss :[rsp+20]
			RSI = dump[R8 * 4] & 0xFF;
			RAX = RBP;
			RSI -= 4; 
			printf("##############dump RSI == %llx\n", RSI);
			printf("##############dump R8 == %llx\n", R8);
		}
		printf("Loop Escape RCX = %d\n", RCX);
		printf("RDI = %llX\n", RDI);
		R15 ^= R15;

		RBP++;
		RDI--; // 한단어당 쓰이는 루프 카운터
		RBX = RDI;
		RAX &= RAX;
		if (RAX == 0)
		{
			goto _escape_char;
		}
		else
		{
			// lea rdx, [0x00007FF726B555DC]
			puts("ㄹ"); // %u3139 ('ㄹ') 
		}
		printf("RBP = %llX\n", RBP);
		printf("LOOP COUNT  RBX = %llX\n", RBX);

		// 한번 더
	_escape_char:
		// EBX == RSI 
		// 좀있다 적어야함 


		printf("****RSI = %llX\n", RSI);
		RAX = 0x2AAAAAAB;
		RAX *= RBX;
		printf("RAX = %llX\n", RAX);
		RDX >>= 1;
		printf("RDX = %llX\n", RDX);
		RAX = RDX;
		RBX -= RAX;
		printf("RBX = %llX\n", RBX);

		// 여기 조금 수정이 필요함 
		wprintf(L"Before = %s\n", data[0]);
		puts("Converting....");

		// 흠 과연 
		if (RBX < 0xB)
		{
			//RAX = RCX;
			switch (RBX)
			{
			case 0:
				wprintf(L"%s\n", dummy0);
				break;
			case 1:
				wprintf(L"%s\n", dummy1);
				break;
			case 2:
				wprintf(L"%s\n", dummy2);
				break;
			case 3:
				wprintf(L"%s\n", dummy3);
				break;
			case 4:
				wprintf(L"%s\n", dummy4);
				break;
			case 5:
				wprintf(L"%s\n", dummy5);
				break;
			case 6:
				wprintf(L"%s\n", dummy6);
				break;
			case 7:
				wprintf(L"%s\n", dummy7);
				break;
			case 8:
				wprintf(L"%s\n", dummy8);
				break;
			case 9:
				wprintf(L"%s\n", dummy9);
				break;
			case 0xA:
				wprintf(L"%s\n", dummyA);
				break;
			}
		}

	}
	system("pause");
}

 

 

 

 

4부 에서는 Dynamic 한 환경에서 적용될 수 있게 커스터마이징을 해보자.

 

'0x02 Reverse Engineer > 0x03. Etc' 카테고리의 다른 글

CRACKME constant ver 01 write up  (0) 2020.07.04
CRACKME constant ver 01  (0) 2020.07.04
lyl -2부  (4) 2020.04.30
lyl -1부  (9) 2020.04.30
Rootme Prob . ELF x86 - KeygenMe  (0) 2020.02.06