기본적으로 롤코타2 언팩과다르진 않다
사진과 함께 쓰려고 했는데 귀찮아서 나중에 하기로
iat는 rdata 시작에 있음
rdata 기준으로 iat 다시 작성
4d11c7 ;oep
4d6000 ;iat 시작
002f0 ;길이
scylla를 사용하려고 했으나 작동이 안되서 ollydumpex랑 imprec을 사용함
*imprec의 경우 400000을 빼줄 필요가 있음
oep는 0x0000000~0xFFFFFFF 까지 범위의 exception을 무시하고
getversion에 bp걸고 bp에서 back to user code를 하다보면 oep가 근처에 있다.(롤코타2 참조)
securom 4.x에서 5.x 언팩은 imports 복구만 조심하면 어렵지 않다
기본적으로 롤코2에서 변형된것이기 때문에 롤코2를 언팩하고 나면 도움이 된다.
기본적으로 securom은 imports redirect를 하는데
call ds:[xxxx] 패턴이랑 그냥 call xxxx 패턴이 있음
1. 0xE8: CALL rel32 - Call near, relative, displacement
2. 0xFF /2: CALL r/m32 - Call near, absolute indirect, address in r/m32
3. 0x9A: CALL ptr16:32 - Call far, absolute, address in operand
4. 0xFF /3: CALL m16:32 - Call far, absolute indirect address in m16:32
FFxx로 시작하는 absolute 점프이고, E8xx로 시작하는건 relative점프이므로 계산해줄 필요가 있다.
계산은 간단한데 call 명령어가 존재하는 주소+ call 명령어가 가르키는 주소+ 5(call 명령어의 주소) = 목적지 주소 이다.
로코모션에선 call을 리다이렉션하는 곳이 크게 두곳이 있다
첫번째는 바로 이곳
E8 92 8F E3 00 call sub_12408A0
.bxfkm:012C5A48 70 0C 24 01 off_12C5A48 dd offset sub_1240C70 ; DATA XREF: sub_11E0EB0+21199w
.bxfkm:012C5A48 ; sub_11E0EB0+211ABw ...
.bxfkm:012C5A4C A0 08 24 01 dd offset sub_12408A0
.bxfkm:012C5A50 A0 08 24 01 dd offset sub_12408A0
.bxfkm:012C5A54 B0 0A 24 01 dd offset sub_1240AB0
.bxfkm:012C5A58 A0 08 24 01 dd offset sub_12408A0
.bxfkm:012C5A5C B0 0A 24 01 dd offset sub_1240AB0
.bxfkm:012C5A60 B0 0A 24 01 dd offset sub_1240AB0
.bxfkm:012C5A64 70 0C 24 01 dd offset sub_1240C70
.bxfkm:012C5A68 A0 08 24 01 dd offset sub_12408A0
.bxfkm:012C5A6C B0 0A 24 01 dd offset sub_1240AB0
.bxfkm:012C5A70 B0 0A 24 01 dd offset sub_1240AB0
.bxfkm:012C5A74 70 0C 24 01 off_12C5A74 dd offset sub_1240C70 ; DATA XREF: .bxfkm:0129F33Er
.bxfkm:012C5A78 B0 0A 24 01 dd offset sub_1240AB0
.bxfkm:012C5A7C 70 0C 24 01 dd offset sub_1240C70
.bxfkm:012C5A80 70 0C 24 01 dd offset sub_1240C70
.bxfkm:012C5A84 A0 08 24 01 dd offset sub_12408A0
.bxfkm:012C5A88 A0 08 24 01 dd offset sub_12408A0
.bxfkm:012C5A8C B0 0A 24 01 dd offset sub_1240AB0
.bxfkm:012C5A90 B0 0A 24 01 dd offset sub_1240AB0
.bxfkm:012C5A94 70 0C 24 01 dd offset sub_1240C70
.bxfkm:012C5A98 B0 0A 24 01 dd offset sub_1240AB0
.bxfkm:012C5A9C 70 0C 24 01 dd offset sub_1240C70
.bxfkm:012C5AA0 70 0C 24 01 dd offset sub_1240C70
.bxfkm:012C5AA4 A0 08 24 01 dd offset sub_12408A0
여러개의 함수 같지만 따지고 보면 함수 3개에 불가하다
두번째는 바로 이곳
.bxfkm:012A8C08 00 00 AF 01 off_12A8C08 dd offset sub_1AF0000 ; DATA XREF: sub_11E0EB0+2A502w
.bxfkm:012A8C0C 00 00 B0 01 dd offset sub_1B00000
.bxfkm:012A8C10 00 00 B1 01 dd offset sub_1B10000
.bxfkm:012A8C14 00 00 B2 01 dd offset sub_1B20000
.bxfkm:012A8C18 00 00 B3 01 dd offset sub_1B30000
.bxfkm:012A8C1C 00 00 B4 01 dd offset sub_1B40000
.bxfkm:012A8C20 00 00 B5 01 dd offset sub_1B50000
.bxfkm:012A8C24 00 00 B6 01 dd offset sub_1B60000
.bxfkm:012A8C28 00 00 B7 01 dd offset sub_1B70000
.bxfkm:012A8C2C 00 00 B8 01 dd offset sub_1B80000
.bxfkm:012A8C30 00 00 B9 01 dd offset sub_1B90000
.bxfkm:012A8C34 00 00 BA 01 dd offset sub_1BA0000
이런식으로 함수가 엄청 많은데 결국 0x11DD7DE 함수를 호출한다
이 함수들은 함수 끝부분에
mov xxxx, eax 혹은 jmp eax와 같이
eax에 redirect된 api의 호출 주소를 넣기 때문에
그곳에 bp를 걸고 eax를 관찰하면 어디를 호출 할지 알 수 있다.
문제는 이걸 어떻게 복구하느냐는 건데
(롤코타2에서도 사용한) securom 언팩 가이드에 있는 asm코드를 변경해서 사용했다.
롤코타2 언팩에서도 언급했지만, iat 복구에 일종의 순서?가 있어서
oep 근처인 0x4d1000에서 먼저 redirect call를 복구하고 0x400000에서 다시 실행해서 복구하는것이 중요하다.
첫번째 패치
0xBA0000으로 가서 다음과 같이 작성하고 new origin을 설정한다.
mov ecx, 0x4d1000 ;text 섹션 시작
cmp word ptr ds:[ecx], 0x15ff ;FF 15 ?? 5A 2C 01 call ds:off_12C5A?? 이면
jne 0x00BA0054 ;inc ecx로 이동
cmp byte ptr ds:[ecx+3], 0x5a
jne 0x00BA0054 ;inc ecx로 이동
cmp word ptr ds:[ecx+4], 0x012c
jne 0x00BA0054 ;inc ecx로 이동
mov dword ptr ds:[0xba0090],ecx ;store ecx
jmp ecx ;jump to ecx
mov ecx, dword ptr ds:[0xba0090] ;restore ecx ;나중에 여기로 이동되게 설정
mov ebx,eax
shr ebx, 0x1c
cmp bl, 0x7 ; 주소가 7x xx xx xx 이면
je ba003c ;iat 판별코드로 이동
mov dword ptr ds:[ecx+2], eax ;eax 값을 ecx+2에 기록
mov ebx, 0x0
jmp ba0053 ;nop으로 이동
mov ebx, 0x4d6000 ;iat start
cmp dword ptr ds:[ebx],eax ;ebx가 가르키는 값이랑 eax랑 비교
je ba0050 ;찾으면(ebx가 가르키는 값이랑 eax랑 같은 값이면) mov dword ptr ds:[ecx+2], ebx로 이동
inc ebx ;ebx 증가
cmp ebx, 0x4D62F0 ;iat end??
jne ba0041 ;iat 끝이 아니면 cmp dword ptr ds:[ebx],eax로 다시 이동해서 비교
int 3 ;error thunk not found ;함수 미발견 오류
mov dword ptr ds:[ecx+2], ebx ;ecx+2자리에 주소를 넣는다 FF 15 XX XX XX XX 형식임
nop ;로깅용 nop 코드
inc ecx ;ecx 증가 (현재 가르키는 바이트)
cmp ecx, 0x505000 ;section 끝 까지 반복
jne ba0005
int 3 ; completed
01240957에 hw bp걸고, command text에 eip=00ba0022;run 작성
01240D27에 hw bp걸고, command text에 eip=00ba0022;run 작성
01240B7C에 hw bp걸고, command text에 eip=00ba0022;run 작성
nop에 hw bp를 걸고 log "ecx: 0x{x:ecx}: eax: 0x{x:eax} ebx: 0x{x:ebx}";run을 해준다
그리고 F9를 눌러 실행하고 0x4d1000을 0x400000으로 바꿔서 한번 더 실행해준다.
두번째 패치
두번째 코드
0xBA1000 로 이동 아래의 값을 작성후 new origin 설정
0x4d1000으로 바꾸고 0x400000으로 바꿔서 다시 실행
mov ecx, 0x400000 ;text 섹션 시작
cmp word ptr ds:[ecx], 0x15ff ;FF 15 ?? 5A 2C 01 call ds:off_12C5A?? 이면
jne 0x00BA103f ;inc ecx로 이동
cmp byte ptr ds:[ecx+3], 0x8c
jne 0x00BA103f ;inc ecx로 이동
cmp word ptr ds:[ecx+4], 0x012a
jne 0x00BA103f ;inc ecx로 이동
mov dword ptr ds:[0xba1090],ecx ;store ecx
jmp ecx ;jump to ecx
mov ecx, dword ptr ds:[0xba1090] ;restore ecx ;나중에 여기로 이동되게 설정
mov ebx, 0x4d6000 ;iat start
cmp dword ptr ds:[ebx],eax
je ba103c
inc ebx
cmp ebx, 0x4D62F0 ;iat end??
jne ba102d
int 3 ;error thunk not found
mov dword ptr ds:[ecx+2], ebx ;eax 값을 ecx+2에 기록
inc ecx ;ecx 증가 (현재 가르키는 바이트)
cmp ecx, 0x505000 ;section 끝 까지 반복
jne ba1005
int 3 ; completed
011DD7DE 에 hw bp걸고 command text에 eip=00ba1022;run 작성
그리고 F9를 눌러 실행하고 0x4d1000을 0x400000으로 바꿔서 한번 더 실행해준다.
이상하게 ep 근처해서 imports를 복구한후 위쪽을 다시 복구해야 문제가 없음
세번째 패치
E8 XX로 호출되는 것은 상대주소로 호출하는 opcode인데 일반적으로 e8로 시작하는것은 5바이트
call ds:[xxxx]형식의 경우 6바이트이기 때문에 자동으로 처리하기 까다롭다.
따라서 이걸 로깅한후 직접 패치했다.
하지만 securom의 경우 6바이트 함수 호출은 5바이트 호출로 바꾸면서 앞뒤로 inc eax나 clc stc같은 의미없는 한바이트를 두므로서 자리를 그대로 보존하고 있기 때문에 그냥 주의를 살펴보고 위치에 맞게 넣으면 된다
1번째코드 처럼 7xxxx 주소면 iat를 돌면서 주소가 7xxx범위면 수정해서 로깅 아니면 그냥 로깅하게 고쳐둘까 했지만
iat를 참조하는 복구가 필요한건 sub 12408a0에만 해당되서 변경하지 않았다.
sub_12408A0,sub_1240C70,sub_1240AB0 세개의 함수가 있기 때문에
cmp edx, 0x012408A0를 함수에 맞게 각각 변경해서 실행해줘야 한다.(코드를 통합해서 실행할 수 도 있겠지만... 그러기엔 게으름...)
0xBA2000 로 이동 아래의 값을 작성후 new origin 설정
mov ecx,0x400000
cmp byte ptr ds:[ecx],e8
jne 0x00BA2029 ;inc ecx 위치로 수정 필요
mov edx, ds:[ecx+1]
add edx, ecx
add edx, 5
cmp edx, 0x012408A0 ;함수(총 3개)에 맞게 바꿔줘야 함
jne 0x00BA2029 ;inc ecx 위치로 수정 필요
mov dword ptr ds:[0xBA2090],ecx
jmp ecx
mov ecx,dword ptr ds:[0xBA2090] <-- 나중에 여기로 이동
nop <- 여기다 bp걸고 log ecx를 한다.
inc ecx
cmp ecx,0x505000
jne 0xBA2005
int 3 <- 여기에 hw bp
(iat복구 코드 포함) sub 12408a0 한정
mov ecx,0x400000
cmp byte ptr ds:[ecx],e8
jne 0x00BA2045 ;inc ecx 위치로 수정 필요
mov edx, ds:[ecx+1]
add edx, ecx
add edx, 5
cmp edx, 0x012408A0 ;함수(총 3개)에 맞게 바꿔줘야 함
jne 0xBA2045 ;inc ecx 위치로 수정 필요
mov dword ptr ds:[0xBA2090],ecx
jmp ecx
mov ecx,dword ptr ds:[0xBA2090] <-- 나중에 여기로 이동
mov ebx, 0x4d6000 ;iat start <- 여기다 bp걸고 log ecx를 한다.
cmp dword ptr ds:[ebx],eax
je ba2040 <-- nop으로 가는 주소
inc ebx
cmp ebx, 0x4D62F0 ;iat end??
jne ba202d <- cmp dword ptr ds:[ebx],eax 위치
int 3 ;error thunk not found
nop <- 여기다 bp걸고 log ecx를 한다.
inc ecx
cmp ecx,0x505000
jne 0xBA2005
int 3 <- 여기에 hw bp
01240957에 hw bp걸고, command text에 eip=00ba2022;run 작성
nop 부분에 log "ecx: 0x{x:ecx}: eax: 0x{x:eax} ebx: 0x{x:ebx}";run
로깅된 결과가 나왔다면 앞뒤에 존재하는 inc eax나 clc stc같은 의미없는 바이트를 확인하고 코드수정
마지막으로 덤프뜨고 imprec으로 복구하면 됨