security/리버싱핵심원리

인라인 패치 - unpackme#1

민사민서 2023. 3. 14. 21:14

[코드 흐름 분석]

0x401000 (EP) // not encoded

0x4010E9 // not encoded

0x401098 // not encoded
디코딩 루프 존재 : 0x4010F5 - 0x401248 xor with 0x44


0x4010BD // not encoded
디코딩 루프 존재: 0x401007 - 0x401085 xor with 0x7

디코딩 루프 존재: 0x4010F5 - 0x401248 xor with 0x11


0x401039 // xor 7에 의해 decoded 된 상태
checksum 계산 (0x4010F5 - 0x401248 변조 여부 확인)


0x40108A // not encoded
디코딩 루프 존재: 0x40124A - 0x40127F xor with 0x17

IAT 복호화


다시 0x401039 // xor 7에 의해 decoded 된 상태
checksum 같으면 OEP Jump

0x40121E (OEP) // xor 0x44, xor 0x11에 의해 decoded 된 상태
DialogBoxParamA 호출하는데, 콜백함수 DlgProc으로 0x4010F5를 건네줌

0x4010F5~0x4011CD 콜백함수 코드 존재  // xor 0x44, xor 0x11에 의해 decoded 된 상태
0x40110A("You must unpack me!!!"), 0x401123("You must patch this NAG!!!") 등 문자열 중간중간 존재

 

* 0x401007 - 0x401085: checksum 계산부분/OEP JUMP 부분은 한 번 암호화되어있다

* 0x4010F5 - 0x401248: OEP 코드+ callback함수 + 문자열들은 두 번 암호화되어있다 => checksum 계산으로 변조 확인

* 0x40124A - 0x40127F: IAT 부분도 한 번 암호화되어있다

 

=> callback함수에서 인자로 넘기는 문자열 주소의 값을 바꾸거나, 문자열들을 직접 수정(in bytes)하면 체크섬 계산에서 걸린다

=> 암호화 안 된 부분에다가 patch된 코드를 추가하고 그쪽으로 실행흐름 바꾼다

 

[코드 패치]

- .text섹션의 Virtual Size 0x280이고 Size of Raw Data 0x400이므로, 0x180(file offset 0x680~0x7FF) 만큼이 사용되지는 않지만 메모리에 로드되는 NULL Padding이다 (메모리에 로딩될 땐 Section Alignment=0x1000 크기로 로드됨)

=> file offset 0x680 ~ 0x7FF에서 수정하면 되겠다

 

1) 패치 코드 집어넣기 (JMP to patch_code → code patch JMP to OEP)

2) 문자열 집어넣기

3) patched code로 점프하도록 기존 코드 수정하기

0x00401083 : E9 96 01 00 00 JMP 0x40121E

0x00401083 : E9 F8 01 00 00 JMP 0x401280

// 단 0x401083~85는 xor 7로 암호화된 상태이므로 HXD에서 수정할 땐 EE FF 06 00 00

// RAW of 0x401083 = 0x1083 - 0x1000 + 0x400 = 0x483

 

[새로 알게 된 점]

1. Ollydbg가 어셈블리 코드를 한 번에 인식 못하는 경우: 우클릭  → Analysis → Analyse code 

OEP(0x40121E)로 점프했는데 해석을 못해서 삽 품 ㅋ

Analyse code 결과

2. 하드웨어 bp 적극 활용 (on execution)

만약 bp 걸고 싶은 코드 위치가 인코딩/디코딩 되는 부분이면 software bp 못 건다 (int3[0xcc] 추가하는 방식이므로)

코드 변경하면 안되는 경우 Hardware breakpoint, on execution 사용!

 

3. Access Violation while reading [address]

- 복호화하려고 하는 주소의 섹션 헤더에 쓰기 권한이 있어야 한다, if not, access violation error

   => 이 경우 .text 섹션 헤더 characteristics에 IMAGE_SCN_MEM_WRITE 속성 있음!

- 잘못된 주소에 참조하거나 읽어오려 하면 access violation error

   => 내 경우 patched code에 MOV ESI, 0x4012B0 이 아니라 0x40012B0 이라 해서 해당 에러 만남 ㅋㅋ

 

4. REP MOVS BYTE PTR ES:[EDI], BYTE PTR DS:[ESI]

1) REP

MOVS, STOS, SCAS 명령어에 한해 해당 명령어를 반복시킨다

REP을 쓰기 위해서는 반복 되는 값을 담아주는 ECX 레지스터 세팅 필요

2) MOVS

ESI가 가리키고 있는 곳의 값을 EDI가 가리키는 곳에 복사(저장)한다

 

ex)

MOV ECX, len

REP MOVS BYTE PTR [EDI], BYTE PTR [ESI]

MOV BYTE PTR [EDI], 0x00 ; terminating null