wonder

정보보안 스터디 - 18주차 6일 - 리버싱 크랙파일 제작 본문

Security/리버싱

정보보안 스터디 - 18주차 6일 - 리버싱 크랙파일 제작

wonder12 2023. 2. 15. 03:24

 

☞ 명령어 종류

 

일단 어제에 이어서

명령어 종류를 살펴보겟습니다.

 

IMUL operand1,2

곱셈 후 1에 저장합니다.

 

IDIV DWORD PTR SS:[EBP-8]

EBP-8값으로 EAX를 나눕니다. 

 

 

 c언어 함수 종류

 

switch

#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "user32")
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nCmd)
{
	int num1 = 3;
    
	switch (num1) {
	case 1:
	MessageBox(NULL, "num1 is 1", "switch 구문(case 1:)", MB_OK);
	break;
    
	case 2:
	MessageBox(NULL, "num1 is 2", "switch 구문(case 2:)", MB_OK);
	break;
    
	case 3:
	MessageBox(NULL, "num1 is 3", "switch 구문(case 3:)", MB_OK);
	break;
    
	default:
	MessageBox(NULL, "num1 is not 1,2,3", "switch 구문(default:)", MB_OK);
	break;
	}
    
	return 0;
}

case 1, 2, 3, default로 나눠서 값을 CMP 각각 비교해서 들어맞으면 해당 메세지 박스를 실행하는 주소로 점프합니다.

 

여기서 IDA로 봤을 때 IDA에서는 EBP-4, EBP+4에 대해서 본인만의 정의를 쓰기 때문에

VAR_4 이나 +일 경우는 EBP를 쓰지않고 int 함수 인자값 그 자체를 써서 값을 저장해놓습니다.

 

ollydbg에서 수정할 때는 점프되는 주소를 변경하여 case를 바꿀 수 있습니다. 

 

 

반복 조건문

보통 증감일 때 많이 사용합니다.

ollydbg에서 봤을 때 반복되서 루프되는 부분에 break point를 걸어두고 F9를 눌러 반복실행할 수 있습니다.

 

for

for(num1=0; num1<5; num1++)

 

for 문에서는 비교를하고 만약 5보다 크지 않을 시 계속 이어가기, 5와 같거나 클 시에는 점프합니다.

 

 

while

while(num1<5) {
num1++;
}

 

 

 

 

 점프

ollydbg를 보면서 어떻게 동작하는지 보고

점프는 어디에서 하는지 어떤  상황에서 하는지.

점프하기 전에 CMP로 비교를 합니다.

비교를해서 값이 같을 시에 결과값(리턴값)은 0이나오고 즉 레지스터창에는 ZF(제로플래그)=1이 뜹니다.

여기서

JE 로 설정했다면 같을 시에(ZF=1일 시) 점프를 하게 됩니다. 바로 밑 코드는 실행을 하지 않고 정해둔 주소로 점프합니다.
JNE는 != 같지 않을 때 즉 ZF=1 이 아닐 때 점프하게됩니다.
JGE 는 두개의 값이 num1 >= num2 일 때 점프합니다. 그림으로 연상해서 보면 쉽습니다.
JLE 는 두개의 값이 num1 <= num2 일 때
JE <
JG >

일 때 각각 점프합니다.

 

 

 

 

 

 어셈블리어 데이터 수정

 

 

ollydbg에서 데이터 수정이 가능합니다.

ZF 제로플래그는 레지스터창에서 수정했음에도 불구하고 왜 수정된 파일 저장이 안되는지 모르겠지만

실행은 우회하여 잘 됩니다.

1. 레지스터 창 값 수정

2. 어셈블리 명령어에서 대입할 인자값을 수정 (EX: MOV EBP-4, 3 > 5)

하면 CMP 5 = 5 로 같게 만들어 점프하던 내용을 반대로 점프가 불가하게 만들 수 있습니다.

3. 점프하는 주소위치를 임의로 수정

4. 명령어를 수정(EX: JLE > JGE)

 

 

저장할 때는

copy all modification > save > example_crack.exe 저장

 

 

 

 

 

 

 

위험성 및 시나리오

이렇게 어셈블리어를 편집하는 것은

좋은 방향으로 쓰면 프로그램 패치가 되지만

나쁜 방향으로는 3일남은 프로그램 기간을 연장하여 100일로 수정하는 등의 크랙을 제작하거나, 악성코드를 카피하여 제작할 수 있으며, 불법으로 프로그램 복제한다거나 할 수 있습니다. 

 

 

 

 

 IDA 뷰어

분석 프로그램 중에서

IDA (PRO) 는 그래프 트리구조로 명령어를 한눈에 확인할 수 있는 프로그램입니다.

예를 들어 점프할 때는 어디로 가는지 두갈래로 나눠서 보여주고 while 반복문에서 ADD 명령을 실시한뒤 돌아가는 것 까지 쉽게 파악할 수 있습니다.

또한 OLLY와 다른점은 OLLY같은 경우에는 하나하나씩 BREAKPOINT를 걸어 실행하면서 프로그램이 어떻게 동작하는지 확인하는 동적 분석인데 IDA는 그렇지 않은 정적분석입니다.

그래서 IDA를 먼저 보고 프로그램 구조를 빠르게 파악하고 ollydbg로 2차적으로 정적분석하는 것이 순서입니다.

 

물론 코드 목록순으로 보고 분석할 수도 있지만 그럴려면 ollydbg로 보는것이 더 편하고 사용하는 의미가 없습니다.

 

 

 

 

 

 

 패킹

packing unpacking

개발자들이 만약 모든 프로그램을 어셈블리어라도 언어를 분석가능하게 한다면 어떻게 될까요? 

그러면 거의 모든해커가 리버싱을 공부해서 프로그램을 역방향으로 분석해서 크랙을 만들거나 소스코드 까지 예측해서 만들어서 악용할 것입니다. 그에 따라 개발을 하는 가치까지 사라질 것입니다.

이를 방지하기 위해서 분석을 어렵게 할 수 있도록 packing 작업을 하고 제공하는 것입니다.

packing은 압축하는 작업이여서 용량도 작아지고 실행도 가능하지만 분석할 때 HxD, PEview 파일 내용을 봤을 때 분석이 어렵습니다. 여기서의 분석이란 예를 들어 프로그래밍 코드 자체가 보기 어려우니까 HxD 로 편집이 불가능할 것입니다. 또는 PEview에서 중요한 IAT(Import Address Table) 즉 관련 dll파일을 가져와서 함수목록을 확인하지 못하고 어떤 게 들어있는지 확인하지 못하는 것을 말합니다. user32.dll을 가져왔는지, 그 중에서 load(), getprocaddress()함수를 썼는지 그런 것등 을 확인하지 못합니다.

한번 원본 파일이랑 확인해보면 imagebase는 같지만 여러 data의 값이 살짝씩 다릅니다.

 

upx 패킹은 워낙 오래되었고 해서 unpacking하는 방법이 나와있고 시도가 수월합니다.

강력한 패킹 도구로는 더 안보이게 압축할 수 있습니다. unpack 방법을 찾는 것 또한 어려울 것입니다.

 

 

패킹 

upx example.exe -o example_pack.exe

 

언패킹

upx -d example_pack.exe -O example_unpack.exe

 

 

exeinfo 에서섹션 위치와 entry point가 바뀐것을 확인하고

원본 파일과 비교해볼 수 있습니다.

 

ollydbg프로그램을 봤을 때

실제 명령어

패킹되는 파일의 명령어는 PUSHAD, POPAD가 있습니다.

레지스터 8개를 스택에다가 백업해두고(PUSH) 나중에 복원하기위해서 백업해둡니다.

마지막에 unpack과정에서 POPAD로 레지스터를 복원합니다. 

 

 

 

ollydbg packing

이렇게 패킹 프로그램 이용해서 하는 것이 가장 베스트지만 

그렇게 사용할 수 없거나 다른 대안이 필요한 경우에는 ollydbg를 사용할 수도 있습니다.

ollydbg에서 dump 시켜 dump파일을 생성합니다.

dump 자체로도 분석은 할 수 있지만 IAT목록을 불러올수는 없기 때문에 실행은 안되므로 실행파일을 생성해야합니다.

plugin > dump

 

 

 

importsec

심슨 모양의 프로그램입니다.

이 프로그램은 dump 된 파일을 넣고 원본파일을 연결해주면

하면 _가 붙어서 exe 파일이 생성되면서 기능을 사용하면서 unpacking 됩니다.

이 때 PEview 분석을 했을 때 약간의 주소 위치나 값이 다릅니다.

하지만 똑같이 거의 구성되어있고 분석이 가능한 수준이기 때문에 괜찮습니다.

 

 

 

 

 

 

+ 어셈블리어, 리버싱 개념 보충)

 

 

소스코드를 실행파일로 만들기위해

컴파일을 한다는 말은 사람만이 읽을 수 있는 소스코드를 기계가 읽을 수 있도록 기계어로 변환시키고

바이너리 파일을 읽어 실행시키는 것입니다. 



즉 exe, ELF 같은 확장자는 바이너리 파일입니다.

여기서 2진수라고 하지 않았나? 왜 16진수가 나오지? 라고 의문을 가질 수 있는데

2진수로 실제로 보여준다면 너무 길어서 표현상으로는 16진수로 하고 실제로는 2진수로 처리하고있는 겁니다.

 0x8d를 2진수로 바꿔보면 00100 ~ 엄청길어짐.

 




어셈블리파일을 보면

주소 부분이있고/ 어셈블리 명령어 부분이 있고/ 값 부분이 있습니다. 

값부분이 기계어 2진수로 명령어 부분이랑 1:1로 바꿀 수 있습니다. 

 

어셈블리언어를 기계어라고 얘기하는 이유가 이것 때문입니다. 
그러니까 정확히 말하면 어셈블리어 는 바이너리 2진수입니다. 


CPU옆에 레지스터가 붙어서 계산할 때 레지스터 값에 저장을 해둡니다.
push 데이터를 넣어라. 저장.
pop 맨위에있는 값을 가져와라. 꺼냄.

push ebx 했을 떄 데이터 값이
스택 주소쪽에 들어가는데 거꾸로 들어갑니다.
리틀 엔디언 방식으로 
pop하면 저장된 EBX값을 원상태로 ff ~ 로 가져옵니다. 


해커들은 소스코드가 없고 프로그램 밖에 없으니 분석해서 c소스코드가 그려지도록 하려고 시도합니다.
이런것을 핸드레이라고 부릅니다.

사실 IDA 유로버전에 hex 레이라고 구현해주는 게 있긴합니다.
없다면 디버깅툴 기드라도 사용하기에 괜찮습니다.

 


컴파일 언어(c, java) vs 인터프리터 언어(python, js)
인터프리터 언어는 컴파일이 필요없습니다. 원래는 C언어같은 경우는 0101 컴파일 과정을 한 번 거치지만 
파이썬 같은 인터프리터 언어는 애초에 소스코드를 작성할 때 최적화되어서 한줄한줄 코드를 넣으면 엔진이 바로 알아서 계산합니다. 즉 파이썬은 코드 짜고 실행 바로 가능합니다.

전체로 봤을 때는 c언어가 만들어놓고 한번에 컴파일해버리면 되기 때문에 더 빠릅니다.


 

 

 

Comments