티스토리 뷰

728x90
반응형

[Reversing] Inline Code Patch


[Reversing] Inline Code Patch ②


원하는 코드를 직접 수정하기 어려운 경우 코드 케이브라고 하는 패치 코드를 삽입한 후 실행해 프로그램을 패치시키는 기법을 인라인 코드(Inline Code Patch)라고 합니다.

또 하나의 개념은 코드 게이브(Code Cave) 입니다. 

흐름을 변경하여 삽입된 코드 영역을 거쳐서 수행되도록 하는 기법을 말합니다.


unpackme#1.aC.exe

위 파일을 통해 실습을 할 것입니다.

[프로그램 실행시 팝업창]


- 살펴보니, 텍스트 박스에 unpack me와 같은 문자가 보입니다.

- x64 dbg를 통해 살펴보겠습니다.


1. x64 dbg & 흐름분석

- EntryPoint로 이동을 하겠습니다.

401000 PUSHAD

- PUSHAD를 통해 레지스터의 값을 스택에 저장했습니다.

401001 CALL <UNPACKME#1.AC.SUB_4010E9>

- 4010E9로 따라가도록 하겠습니다.

[EP코드]


4010E9 MOV EAX, UNPACKME#1.AC.4010F5

- 4010F5를 EAX에 저장합니다.

4010EE PUSH EAX

- EAX를 스택에 저장합니다.

4010EF CALL <UNPACKME#1.AC.SUB_40109B>

- 40109B로 따라가도록 하겠습니다.

[4010E9 주소]


40109B PUSH EAX

40109C MOV EBX, EAX

- 함수의 스택 프레임을 생성합니다.

- EBX에 4010F5를 저장합니다

40109E MOV ECX, 154

- ECX에 154를 저장하는데 ECX가 0이 될때까지 아래 루프를 실행할 것 같습니다.

4010A3 XOR BYTE PTR DS:[EBX], 44

4010A6 SUB ECX, 1

4010A9 INC EBX

4010AA CMP ECX, 0

4010AD JNE UNPACKME#1.AC.4010A3

- 복호화 루프에서 ECX를 1씩 감소시키면서 EBX 값을 1씩 증가 시킵니다.

- XOR 연산을 통하여 복호화가 진행된다는걸 확인할수 있습니다.

- ECX가 0이 되면 루프를 벗어나 4010AF 부터 진행됩니다.

[복호화]

[복호화 루프]


4010AF PUSH EAX

- EAX(4010F5)을 스택에 저장합니다.

4010B0 CALL <UNPACKME#1.AC.SUB_4010BD>

- 4010BD로 따라가도록 하겠습니다.


4010BD PUSH EAX

4010BE MOV EBX, UNPACKME#1.AC.401007

- 함수의 스택 프레임을 생성합니다.

- EBX에 401007을 저장합니다

4010C3 MOV ECX, 7F

- 이전과 같이 ECX에 7F를 저장하는데 ECX가 0이 될때까지 아래 루프를 실행할 것 같습니다.

4010C8 XOR BYTE PTR DS:[EBX], 7

4010CB SUB ECX, 1

4010CE INC EBX

4010CF CMP ECX, 0

4010D2 JNE UNPACKME#1.AC.4010C8

- 첫번째 복호화 루프입니다.

- 401007 ~ 401085 영역까지 복호화를 합니다.

4010D4 MOV EBX, EAX

4010D6 MOV ECX,154

4010DB XOR BYTE PTR DS:[EBX], 11

4010DE SUB ECX, 1

4010E1 INC EBX

4010E2 CMP ECX, 0

4010E5 JNE UNPACKME#1.AC.4010DB

- 두번째 복호화 루프입니다.

- 4010F5 ~ 401248 영역까지 복호화를 합니다.

- 해당 영역은 이중으로 암호화가 되어있다는걸 확인할수 있습니다.(40109B 함수)

[복호화]

[복호화 루프]


4010B5 PUSH EAX

- EAX(4010F5)을 스택에 저장합니다.

4010B6 CALL <UNPACKME#1.AC.SUB_401039>

- 401039로 따라가도록 하겠습니다.


401039 PUSH EAX

40103A MOV EBX, EAX

- 함수의 스택 프레임을 생성합니다.

- EBX에 4010F5를 저장합니다

40103C MOV ECX, 154

- ECX에 154를 저장합니다.

401041 MOV EDX, 0

- EDX 값을 0으로 만듭니다.

401046 ADD EDX, DWORD PTR DS:[EBX]

- 4byte 단위로 값을 읽어온 뒤 ADD 연산을 실행합니다.

401048 SUB ECX, 1

40104B INC EBX

40104C CMP ECX, 0

40104F JNE UNPACKME#1.AC.401046


401062 CMP EDX, 31EB8DB0


401062 CMP EDX, 31EB8DB0

- EDX(CRC 체크섬) 값과 31EB8DB0을 비교합니다.

401068 JE UNPACKME#1.AC.401083

- 31EB8DB0과 같으면 JE로 인해 401083 주소로 점프합니다.

40106A PUSH 30

40106C PUSH UNPACKME#1.AC.401032

401071 PUSH UNPACKME#1.AC.401009

401076 PUSH 0

401078 CALL <JMP .&MessageBoxA>

40107D PUSH EAX

40107E CALL <JMZ .&ExitProcess>

- 서로 다른 값일 경우 아래와 같은 "Error" 알림창을 띄우게 됩니다.

401083 JMP UNPACKME#1.AC.40121E

- 40121E로 점프해보겠습니다.


OEP(Original Entry Point) 

40121E PUSH 0

401220 CALL <JMP. &GetModuleHandleA>

401225 MOV DWORD PTR DS:[403018], EAX

40122A PUSH 0

40122C PUSH UNPACKME#1.AC.4010F5

- DLGPROC lpDialogFunc

401231 PUSH 0

- HWWD hWndParent

401233 PUSH UNPACKME#1.AC.403024

- LPCTSTR lpTemplate

401238 PUSH DWORD PTR DS:[403018]

- HINSTANCE hInstance

40123E CALL <JMP .&DialogBoxParamA>

- 다이얼로그 중 lpDialogFunc는 다이얼로그 박스 프로시저 주소를 가르킵니다.

401243 PUSH EAX

401244 CALL <JMP .&ExitProcess>

- GetModuleHandleA, DialogBoxParamA, ExitProcess 3개의 API 함수를 호출했습니다.

- 스택에 역순으로 40122C 주소가 lpDialogFunc의 4010F5 값 입니다.

- 위 40122C(lpDialogFunc) 통하여 문자열을 띄우게 되는걸 알아냈고, 코드 케이브를 이용하여 패치를 해보겠습니다.



728x90
반응형
댓글
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today