switch generator

안상준·2025년 3월 21일

Virtualize Deobfuscator

목록 보기
3/14

Switch Generator

llm 학습을 위한 데이터셋을 생성이 필요하다.
지난주 switch의 특징에 대하여 살펴 보았고, 이번주는 llm 학습을 위하여 switch구조를 가진 어셈블리 코드를 생성하는 활동을 하였다.
데이터셋 생성 방법으로 여러가지가 있는데

  • 인터넷에 있는 switch문을 크롤링하여 가져올 수 있다.
  • 코드를 이용하여 다양한 switch문을 작성한다.
  • 직접 하드코딩

인터넷을 찾아본 결과 switch문을 모아둔 사이트는 찾기 어려워 두 번째 방법을 채택하였다.

아래 python 코드들은 perplexity를 활용하여 생성한 코드들을 수정하여 작성 하였다.

nested_switch_generator

def generate_nested_switch(depth, num_cases):
    switch_code = "    switch (value) {\n"
    for i in range(1, num_cases + 1):
        switch_code += f"        case {i}:\n"
        if depth > 1:
            switch_code += f"            switch (sub_value) {{\n"
            for j in range(1, num_cases + 1):
                switch_code += f"                case {j}:\n"
                switch_code += f"                    printf(\"{i}-{j} executed\\n\");\n"
                switch_code += f"                    break;\n"
            switch_code += "            }\n"
        else:
            switch_code += f"            printf(\"Case {i} executed\\n\");\n"
        switch_code += f"            break;\n"
    switch_code += "        default:\n"
    switch_code += "            printf(\"default executed\\n\");\n"
    switch_code += "            break;\n"
    switch_code += "    }\n"
    return switch_code

# 여러 개의 switch 문을 생성하여 저장
num_files = 10  # 생성할 파일 개수
switch_depth = 10

for i in range(1, num_files+1):
    for j in range(1, switch_depth + 1):
        filename = f"./data/nested_switch/nested_switch_{i}_{j}.c"
        with open(filename, "w") as f:
            f.write("#include <stdio.h>\n\n")
            f.write("int main() {\n")
            f.write(f"    int value = {i}, sub_value = {j};\n")
            f.write(generate_nested_switch(i, j))
            f.write("    return 0;\n}\n")

# 생성된 파일 목록 출력
[f"nested_switch_{i}.c" for i in range(1, num_files + 1)]

먼저 중첩 switch문이다 생성 결과는

#include <stdio.h>

int main() {
    int value = 2, sub_value = 1;
    switch (value) {
        case 1:
            switch (sub_value) {
                case 1:
                    printf("1-1 executed\n");
                    break;
            }
            break;
        default:
            printf("default executed\n");
            break;
    }
    return 0;
}

이런 식으로 생성이 되며

총 10*10=100개를 생성하는 코드를 작성 하였다.

computational_switch

import os

def generate_computational_switch(num_cases=5):
    """ computational switch-case generator """
    switch_code = "    switch (value) {\n"
    for i in range(1, num_cases + 1):
        switch_code += f"        case {i}: {{\n"
        switch_code += f"            int result;\n"
        if i % 5 == 1:
            switch_code += f"            result = value * 10;\n"
            switch_code += f"            printf(\"{i} selected, result: %d\\n\", result);\n"
        elif i % 5 == 2:
            switch_code += f"            result = value + 5;\n"
            switch_code += f"            printf(\"{i} selected, result: %d\\n\", result);\n"
        elif i % 5 == 3:
            switch_code += f"            result = value - 3;\n"
            switch_code += f"            printf(\"{i} selected, result: %d\\n\", result);\n"
        elif i % 5 == 4:
            switch_code += f"            result = value / 2;\n"
            switch_code += f"            printf(\"{i} selected, result: %d\\n\", result);\n"
        else:
            switch_code += f"            result = value * value;\n"
            switch_code += f"            printf(\"{i} selected, square: %d\\n\", result);\n"
        switch_code += "            break;\n        }\n"
    switch_code += "        default:\n"
    switch_code += "            printf(\"default\\n\");\n"
    switch_code += "            break;\n"
    switch_code += "    }\n"
    return switch_code

# 여러 개의 computational switch 파일 생성
num_files = 10  # 생성할 파일 개수
switch_cases = 10  # 각 switch 문의 case 개수

for i in range(1, num_files + 1):
    for j in range(1, switch_cases + 1):
        filename = f"./data/computational_switch/computational_switch_{i}_{j}.c"
        with open(filename, "w") as f:
            f.write("#include <stdio.h>\n\n")
            f.write("int main() {\n")
            f.write(f"    int value = {i * j};\n")
            f.write(generate_computational_switch(j))
            f.write("    return 0;\n}\n")

# 생성된 파일 목록 출력
[f"computational_switch_{i}_{j}.c" for i in range(1, num_files + 1) for j in range(1, switch_cases + 1)]

이번에는 switch문의 case안에서 연산을 하도록 하는 코드를 추가해 주었다.

#include <stdio.h>

int main() {
    int value = 1;
    switch (value) {
        case 1: {
            int result;
            result = value * 10;
            printf("1 selected, result: %d\n", result);
            break;
        }
        default:
            printf("default\n");
            break;
    }
    return 0;
}


이렇게 10*10=100개의 c코드를 생성해 주었다.

3d_switch_generator

def generate_3d_switch(num_cases, x, y, z):
    """ 3 nested switch-case generator """
    switch_code = "    switch (value_1) {\n"
    for i in range(1, x + 1):
        switch_code += f"        case {i}:\n"
        switch_code += f"            switch (value_2) {{\n"
        for j in range(1, y + 1):
            switch_code += f"                case {j}:\n"
            switch_code += f"                    switch (value_3) {{\n"
            for k in range(1, z + 1):
                switch_code += f"                        case {k}:\n"
                switch_code += f"                            printf(\"{i}-{j}-{k}\\n\");\n"
                switch_code += f"                            break;\n"
            switch_code += "                    }\n"
            switch_code += "                    break;\n"
        switch_code += "            }\n"
        switch_code += "            break;\n"
    switch_code += "    }\n"
    return switch_code

# 여러 개의 3중 중첩 switch문 C 코드 파일 생성
num_files = 10  # 생성할 파일 개수 (10*10*10)
num_cases = 3    # 각 switch 문의 case 개수
num_cnt = 0;

for i in range(1, num_files + 1):
    for j in range(1, num_files + 1):
        for k in range(1, num_files + 1):
            num_cnt += 1

            # C 코드 생성
            c_code = f"#include <stdio.h>\n\nint main() {{\n"
            c_code += f"    int value_1 = {i};\n"
            c_code += f"    int value_2 = {j};\n"
            c_code += f"    int value_3 = {k};\n"
            c_code += generate_3d_switch(num_cases, i, j, k)
            c_code += "    return 0;\n}\n"

            # 파일에 저장
            filename = f"./data/3d_switch/3d_switch_{num_cnt}.c"
            with open(filename, "w") as f:
                f.write(c_code)

            print(f"파일 {filename} 생성됨")
    

# 생성된 파일 목록 출력
[f"3d_switch_{i}.c" for i in range(1, num_files + 1)]

해당 코드는 3중 중첩 switch문을 생성하는 코드이다.

#include <stdio.h>

int main() {
    int value_1 = 2;
    int value_2 = 1;
    int value_3 = 3;
    switch (value_1) {
        case 1:
            switch (value_2) {
                case 1:
                    switch (value_3) {
                        case 1:
                            printf("1-1-1\n");
                            break;
                        case 2:
                            printf("1-1-2\n");
                            break;
                        case 3:
                            printf("1-1-3\n");
                            break;
                    }
                    break;
            }
            break;
        case 2:
            switch (value_2) {
                case 1:
                    switch (value_3) {
                        case 1:
                            printf("2-1-1\n");
                            break;
                        case 2:
                            printf("2-1-2\n");
                            break;
                        case 3:
                            printf("2-1-3\n");
                            break;
                    }
                    break;
            }
            break;
    }
    return 0;
}

이렇게 switch문이 생성이 되게 된다.

101010=1000개의 switch문이 생성이 된다.

asm_generator

마지막으로 생성된 c코드를 assembly코드로 변환해 주는 코드이다.

import subprocess
import os

file_name = "3d_switch"

def compile_to_assembly(filename):

    # C 파일 이름에서 확장자 제거
    base_filename = os.path.splitext(os.path.basename(filename))[0]

    # 어셈블리 코드를 저장할 디렉토리
    output_dir = f"./data/assembly_code/{file_name}"

    # GCC로 어셈블리 코드 생성
    compile_command = ["gcc", "-S", filename, "-o", f"{output_dir}/{base_filename}.s"]
    try:
        subprocess.run(compile_command, check=True)
        print(f"{filename} 어셈블리 코드 생성 성공")
    except subprocess.CalledProcessError as e:
        print(f"{filename} 어셈블리 코드 생성 실패: {e}")

# C 파일 목록
c_files = [f"./data/3d_switch/{file_name}_{i}.c" for i in range(1, 1001)]

# 각 C 파일을 어셈블리 코드로 변환
for filename in c_files:
    compile_to_assembly(filename)

gcc를 통해 c코드를 .s파일로 컴파일을 수행한다.
file_name 변수와 c_files 부분을 변경하여 컴파일 할 코드들을 변경할 수 있다.

실행 결과로, 잘 실행되는 것을 볼 수 있다.

정리

생성된 코드들은 모두 문법적으로 이상이 없는 것을 확인 하였다.
현재 작성한 코드 들로는 총 1200개 생성 되었고, 코드에 있는 값들을 조정하면 더 많은 수의 switch문을 생성이 가능하다.
상수값을 사용하는 switch문들도 의도대로 잘 생성이 되었다.

Todo

  • assembly 생성하는 코드에서 파일을 가져오는 부분을 편리하게 하기 위해 파일명을 수정할 필요가 있다.
  • 컴파일 옵션을 다르게 하면 좀 더 다양한 assembly code를 생성할 수 있을 것 같다.
  • assembly code의 길이가 상당히 길어 데이터셋으로 사용할 수 있도록 수정할 필요가 있을 것 같다.
  • 좀 더 다양한 switch문을 생성하는 코드가 필요할 것 같다.

0개의 댓글