Tigress Virtualize Analysis - Branch, Function

안상준·2025년 11월 28일

Virtualize Deobfuscator

목록 보기
11/14

이번에는 원본 코드에서 분기문과 함수 콜이 존재할때, 가상화된 코드에서 이를 어떻게 표현하는지 분석해 보았다.

Branch

bubble sort를 가상화 난독화 적용해 보았다.

#include <stdio.h>

int main(void){
        
    int n;
    scanf("%d", &n);
    int arr[10] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
    int i;
    int j;
    int temp;
    n = 10;
    for (i = 0; i < n - 1; i++) {            
        for (j = 0; j < n - i - 1; j++) {                
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
    return 1;
}


해당 핸들러 부분이 분기문 처리하는 부분이다. Opcode의 이름을 봐도 알 수 있다. 먼저 stack top에 있는 정수 값을 이용한 조건문이 존재한다.
만약 참일 경우 opernad의 값 만큼 VPC 값을 증가하게 된다.
아닌 경우는 4만큼 증가하고, stack top을 조정하게 된다.

즉 조건문은 Operand 값을 이용하여 VPC값을 증가시켜 handler를 호출하는 방식으로 동작하게 된다.

Function

이번에는 함수를 호출하는 코드를 가상화 했을 때의 코드를 분석해 보자.

#include <stdio.h>

int add(int x, int y) {
    return x + y;
}

int sub(int x, int y) {
    return x - y;
}

int mul(int x, int y) {
    return x * y;
}

int main() {
    int n;    
    int a = 4, b = 2;
    printf("%d\n", add(a, b));
    printf("%d\n", sub(a, b));
    printf("%d\n", mul(a, b));
    return 1;
}

먼저 사용한 c 코드다.

위 사진은 위의 C 코드를 디스패치 옵션을 switch로 하여 가상화 난독화를 적용한 코드 내에서 함수를 호출하는 부분을 나타내는 코드이다.
해당 코드는 디스패치 구조 (loop-switch) 내부에 있는 함수 호출 처리 핸들러 이며, switch를 이용하여 조건에 맞는 함수를 호출하는 방식으로 동작한다.

main 안에서 사용한 함수는 add, sub, mul, printf 이렇게 4개를 호출하였다. 하지만 swtich의 case문의 개수를 보면 6개 인것을 확인할 수 있다.

먼저 add, sub, mul 함수의 경우

가상화 영역 밖에 original 형태로 작성돼 있다.
#으로 적혀 있는 부분은 원본에서 몇 번째 줄에 작성돼 있었는지 컴파일러에게 알리는 부분이다.

함수 호출 operand로 들어가는 부분은 이전과 마찬가지로 VPC 값을 증가시켜 operand를 가리키도록 하여 사용하는 방식이다.

그럼 나머지 printf는 왜 3개인지 알아보면, 이는 단순히 printf를 3번 호출하였기 때문이다. 이는 동일한 명령어로도 확인해본 결과 무조건 호출한 개수만큼 switch의 case문이 존재하는 것을 확인하였다.

0개의 댓글