VMProtect Virtualization 분석 2

안상준·2025년 7월 21일

VMProtect

목록 보기
3/6

Code

#include <stdio.h>
int main() {
    int a, b;
    scanf("%d %d", &a, &b);
    printf("%d\n", a + b);
    printf("%d\n", a - b);
    printf("%d\n", a * b);
    printf("%d\n", a / b);
    return 0;
}

코드는 이렇게 사용하였고, gcc로 컴파일 하여 vmprotect를 적용하였다.

IDA

Original


먼저 원본 코드를 IDA로 분석한 결과이다. 이를 통해 main함수의 주소를 확인하였다.

Virtualization


함수 보호는 main함수만 진행 하였고, option은 virtualization만 적용하였고 그 외에는 전부 적용하지 않았다.

가상화 난독화를 적용하고 IDA로 열었을때의 시작 부분이다. 값을 stack에 push하고 loc_14017A33A를 호출한다.
해당 위치로 이동하면

이러한 CFG를 볼 수 있다.

Dispatcher


확인해 보면 굉장히 많은 잡음 명령어들이 존재하고 stack에 값을 저장하는 코드들을 보면

push rcx
push rax
push rbx
push r11
push r14
push r13
push rdx
push rbp
push r9
push r10
push rsi

이렇게 레지스터 값들을 push하는 것을 볼 수 있다.

Fetch & Decode

loc_14017AA64:
push    r8
mov     r11b, dil
movsx   rsi, cx
cwd
pushfq
mov     r10, 0
mov     [rsp+arg_20], r10
mov     esi, dword ptr [rsp+arg_78]
adc     r9b, 93h
movsx   rcx, r10w
sbb     r9w, 9A4h
add     esi, 482F2D86h
cqo
bswap   esi
cwd
cmovbe  rdx, rsi
inc     esi
adc     bpl, dl
test    esp, 0F215CBBh
or      ch, 84h
neg     esi
bswap   esi
dec     esi
movzx   r11, r8w
rol     dh, 2
ror     esi, 1
shl     bpl, 0Eh
lea     rsi, [rsi+r10]
cwd
rol     cl, cl
sets    ch
mov     r9, 100000000h
lea     rsi, [rsi+r9]
adc     ebp, esp
movsx   ebp, r15w
shld    rcx, rax, 0BFh
mov     [rsp+arg_70], r15
clc
cmovg   bp, di
neg     r11b
mov     [rsp+arg_78], rdi
and     bp, 0D8Fh
sar     bpl, 31h
mov     rbp, rsp
lea     rcx, [rbp-200h]
or      edx, 10076B87h
and     r8b, r10b
shrd    dx, r10w, 7
and     cl, 0F0h
xchg    r11b, dl
jmp     loc_14017D001

해당 위치에는 r8, flags를 stack에 push하는 것을 볼 수 있다.
중요하게 볼 부분이

rsi레지스터는 instruction pointer로 사용하기 때문에 중요하게 봐야할 부분이라고 생각한다.
가장 처음에 movsx rsi, cx를 수행한다. 중간에 의미없는 연산들이 존재하며 lea rsi, [rsi + r10] 을 수행하는데 처음 cx가 base주소를 나타내는 것이 아닌가 하는 생각이 든다. 그 다음 다시 lea rsi, [rsi+r9]를 실행한다. 명령어 실행을 위해 offset을 더해준 것으로 생각이 든다.

mov rbp, rsp
lea rcx, [rbp-200h]

또 다른 중요한 부분이라 생각드는 곳인데, 정적 분석을 하고 있기 때문에 정확히 어떤 값이 stack에 들어가 있는지는 알 수 없지만 흐름상 rcx가 VMContext를 가리키는 것으로 예측한다.

그 다음 부분을 보면 rsprcx의 값을 넣고 연산을 수행한다.

r11에 주소값을 저장하고

코드의 마지막 부분인 해당 위치로 이동하게 된다.

  • r8d(r8의 하위 32비트) -> rsi
  • r11 -> handler table 시작주소
  • movsxd rdx, dword ptr [r11 + r8*4] -> r8에 저장된 값을 사용하여, handler 주소를 rdx에 저장
  • push rdx, retn -> rdx에 저장된 주소로 분기

실제로 "Inside VMProtect" 블로그를 보면 rsi는 instruction pointer를 가르킨다고 명시돼 있다.

방금 분석한 블럭의 집합점이다. 다른 블럭들에서 VMloop를 통해 fetch 하고 decode 하는 부분이 존재하지 않을까 싶다.

Handler

위 분석을 통해 r11이 handler table이라는 것을 알았다. 그리하여 해당 부분을 분석해 보았다.

보면 엄청나게 많은 값들이 있는 것을 볼 수 있는데 여기 있는 offset값을 이용해여 handler로 이동하게 된다.

0개의 댓글