这是一道来自2020网鼎杯玄武组的逆向题,题目的重难点在分析vm流程。这届比赛我没有参加,看到 一些博客都在分析这道题目,于是在闲暇时间复盘学习一下。
0x01分析首先看一下文件有没有加壳
无壳,拖入ida分析。试着运行一下程序,输入一些数据测试看看结果
1.主函数体分析程序只保留了系统的符号,但是可以根据显示的信息定位到主要函数体
printf("Tell Me Your Flag:n");
scanf("%s", &input, 50i64);
global_var1_unk = sub_1400804A0(0i64);
AntiDebug(); // 反调试,调试模式下会退出程序
if ( strlen(&input) == 42 ) // input的长度限制为42字节
{
AntiDebug();
if ( input == 'f'
&& v8 == 'l'
&& v9 == 'a'
&& v10 == 'g'
&& v11 == '{'
&& v16 == '}'
&& v12 == '-'
&& v13 == '-'
&& v14 == '-'
&& v15 == '-' )
{
AntiDebug();
i_1 = 0;
for ( j = 5; j < 41; ++j ) // 将input填充到input_iArr中,填充方式是忽略flag、{、}和-,按顺序填充
{
if ( *(&input + j) >= '0' && *(&input + j) <= '9' || *(&input + j) >= 'a' && *(&input + j) <= 'f' )
input_iArr[i_1++] = *(&input + j);
}
AntiDebug();
if ( i_1 == 32 )
{
AntiDebug();
v21 = i_1;
if ( (unsigned __int64)i_1 >= 0x64 )
j___report_rangecheckfailure();
input_iArr[v21] = 0;
AntiDebug();
hex_buf = StrToHex((__int64)input_iArr);// 小端序
AntiDebug();
if ( (unsigned __int8)j_check((__int64)hex_buf) )
{
printf("Right flag!n");
}
else
{
AntiDebug();
printf("Wrong flag!n");
AntiDebug();
}
system("pause");
}
else
{
printf("No flag for you!n");
}
}
else
{
printf("No flag for you!n");
}
}
else
{
printf("No flag for you!n");
}
部 分 函 数 根 据 上 下 文 分 析 已 重 定 义 名 字 , 方 便 后 续 分 析 。 textcolor{green}{部分函数根据上下文分析已重定义名字,方便后续分析。} 部分函数根据上下文分析已重定义名字,方便后续分析。
首先简单分析一下vm之前的处理过程:
@line:5处检查用户输入的数据长度和格式,合法输入应该满足 f l a g { x x x x x x x x − x x x x − x x x x − x x x x − x x x x x x x x x x x x } textcolor{orange}{flag{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}} flag{xxxxxxxx−xxxx−xxxx−xxxx−xxxxxxxxxxxx}共42字节。
@line:7根据动态分析可以知道是反调试,大致原理是判断时间差 > 1 m s textcolor{orange}{>1ms} >1ms时表示处于调试状态,然后调用 T e r m i n a t e P r o c e s s textcolor{cornflowerblue}{TerminateProcess} TerminateProcess结束当前进程。需要patch掉反调试,方法是直接在函数头返回。
@line:49的循环是将输入的数据去掉flag、{、-和 }标识,重新组织成新的字符串 x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x textcolor{orange}{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx共32字节,不妨记为input_iArr。
@line:35将input_iArr转成十六进制,结果存放在hex_buf中。例如input_iArr的内容为 A B C D 12345 D D textcolor{orange}{ABCD12345DD} ABCD12345DD的字符串,则hex_buf的内容就是 { 0 x 0 A , 0 x B C , 0 x D 1 , 0 x 23 , 0 x 45 , 0 x D D } textcolor{orange}{{0x0A,0xBC,0xD1,0x23,0x45,0xDD}} {0x0A,0xBC,0xD1,0x23,0x45,0xDD}字节数组。
@line:37进入到校验环节。
2.校验流程分析memset(md5_code_for_hex_buf, 0, 0x14ui64);
memset(md5_code_for_table, 0, 0x14ui64);
MD5((__int64)hex_buf, 16i64, (__int64)md5_code_for_hex_buf, (__int64)&v8);// 对hex_buf进行MD5
v12 = 0;
j_Generate_Table(hex_buf, (unsigned __int8 *)&table);
MD5((__int64)&table, 100i64, (__int64)md5_code_for_table, (__int64)&v8);
for ( j = 0; j < 16; j += 4 ) // 分成4组进行处理
{
_mm_lfence();
re_hex_buf = reverse_bytes((__int64)&hex_buf[j]);// (v[3] << 24) | (v[2] << 16) | v[0]
re_hex_buf_md5 = reverse_bytes((__int64)&md5_code_for_hex_buf[j]);
re_table_md5 = reverse_bytes((__int64)&md5_code_for_table[j]);
v9[v12++] = re_hex_buf_md5;
v3 = j_vm_transform(
(unsigned __int8 *)re_hex_buf,
(unsigned __int8 *)re_hex_buf_md5,
(unsigned __int8 *)re_table_md5);
v9[v12++] = v3;
}
LOBYTE(v4) = j_final_check((__int64)v9);
部 分 函 数 根 据 上 下 文 分 析 已 重 定 义 名 字 , 方 便 后 续 分 析 。 textcolor{green}{部分函数根据上下文分析已重定义名字,方便后续分析。} 部分函数根据上下文分析已重定义名字,方便后续分析。
@line:3想知道如何识别这是一个MD5函数,首先进去看看其代码
if ( CryptAcquireContextW(&phProv, 0i64, 0i64, 1u, 0xF0000000) )
{
if ( CryptCreateHash(phProv, 0x8003u, 0i64, 0, &phHash) )// 非键控算法,散列函数
{
if ( CryptHashData(phHash, pbData, dwDataLen, 0) )
{
pdwDataLen = 4;
CryptGetHashParam(phHash, 4u, v12, &pdwDataLen, 0);
v16 = (BYTE *)sub_14007835E(*(unsigned int *)v12);
v14 = v16;
pdwDataLen = *(_DWORD *)v12;
CryptGetHashParam(phHash, 2u, v16, &pdwDataLen, 0);
for ( j = 0; j < pdwDataLen; ++j )
v21[j] = v14[j];
v17 = v14;
sub_140077413((__int64)v14);
if ( v17 )
{
v14 = (BYTE *)33059;
v18 = 33059i64;
}
else
{
v18 = 0i64;
}
CryptDestroyHash(phHash);
CryptReleaseContext(phProv, 0);
sub_14007528A();
v6 = 1i64;
}
else
{
*v22 = GetLastError();
CryptDestroyHash(phHash);
CryptReleaseContext(phProv, 0);
v6 = 0i64;
}
}
else
{
*v22 = GetLastError();
CryptReleaseContext(phProv, 0);
v6 = 0i64;
}
}
else
{
*v22 = GetLastError();
v6 = 0i64;
}
引用的都是系统库的函数,很容易在网上搜索到这些库函数的定义和功能,然后根据对比输入输出的数据变化就能知道这是个 MD5加密。接着回到校验流程的分析中。
@line:3对 hex_buf进行 md5加密,结果保存在 md5_code_for_hex_buf。
line:5会根据 hex_buf生成一张表,其代码:
G e n e r a t e _ T a b l e textcolor{cornflowerblue}{Generate_Table} Generate_Table:
sum = 0;
for ( j = 0; j < 16; ++j ) // 十六个字节累加,与0x64取模
sum += v12[j];
sum %= 0x64u;
result = (unsigned __int8)sum;
remain = sum;
for ( k = 0; k < 100; ++k ) // 用余数生成100个元素的表
{
v10 = 0;
remain ^= 0xC3u;
table[k] = remain;
for ( l = 0; l < 8; ++l )
v10 ^= ((signed int)remain >> l) & 1;
remain = v10 | 2 * remain;
result = (unsigned int)(k + 1);
}
将 hex_buf的所有元素累加求和,结果记为 sum,然后除以 0x64取余数 remain,后续用 remain生成 100个元素的表 table。即使不知道正确的 hex_buf,但正确的 table必定在这 100个中。接着回到校验流程的分析中。
@line:6对 table进行 md5加密,结果保存在 md5_code_for_table中。
@line:7循环分组处理,将 hex_buf、md5_code_for_hex_buf和 md5_code_for_table平均分成4组,每组4字节,也就是unsigned int型。处理的方法是先分别将这3个数据进行一个逆字节序变换,例如:0xABCDEF10,转换成 0x10EFCDAB,然后进入vm。vm是重头戏,先不着急往里面分析,留到后面,先把校验流程过一遍。
@line:14 v3保存vm的结果,v9是最后的结果。v9内部数据的分布是 2 i textcolor{orange}{2i} 2i位置存放的是 re_hex_buf_md5, 2 i − 1 textcolor{orange}{2i-1} 2i−1位置存放的是 v3,共 32字节长。
line:20 进行最后的判断,与最终的结果进行对比。代码:
for ( j = 0; j < 8; ++j )
{
if ( v6[j] != ans[j] )//v6就是上层函数传进来的v9,ans中保存着正确结果
return 0;
}
从 ans中,我们得到正确的 r e _ h e x _ b u f _ m d 5 = { 0 x C 5 D 83690 , 0 x 978162 E A , 0 x 1932 A 96 C , 0 x 4222669 } textcolor{orange}{re_hex_buf_md5 = { 0xC5D83690 ,0x978162EA ,0x1932A96C ,0x4222669 }} re_hex_buf_md5={0xC5D83690,0x978162EA,0x1932A96C,0x4222669},
正确的 vm结果是 { 0 x 1 F 7902 C C , 0 x 2 F A E 3 D 15 , 0 x C E E B F E 91 , 0 x A F F 6 A F 42 } textcolor{orange}{{0x1F7902CC, 0x2FAE3D15, 0xCEEBFE91, 0xAFF6AF42}} {0x1F7902CC,0x2FAE3D15,0xCEEBFE91,0xAFF6AF42}
到此,总体的校验流程走完了,接下来开始分析vm流程。
3.vm流程分析 ■ vm_transform 分析dest[4] = (unsigned int)table_md5_trans;
dest[2] = (unsigned int)hex_buf_md5_trans;
dest[0] = (unsigned int)hex_buf_trans;
...
v8[0] = dest[0];
v8[1] = dest[2];
v8[2] = dest[4];
vm_entry = malloc(0x48ui64);
if ( vm_entry )
{
ZeroMemory((__int64)vm_entry, 0x48i64);
vm_entry_ref = vm_init((__int64)vm_entry, (__int64)opcode, 4096i64, (__int64)v8);//虚拟机对象初始化
}
else
{
vm_entry_ref = 0i64;
}
v10 = vm_entry_ref;
v9 = vm_entry_ref;
vm_dispatcher((__int64)vm_entry_ref);//虚拟机调度器
v5 = vm_copy((__int64)v9, (__int64)v12)[1];//获取虚拟机处理结果
部 分 函 数 根 据 上 下 文 分 析 已 重 定 义 名 字 , 方 便 后 续 分 析 。 textcolor{green}{部分函数根据上下文分析已重定义名字,方便后续分析。} 部分函数根据上下文分析已重定义名字,方便后续分析。
@line:8 创建虚拟机对象,大小0x48字节。@line:12 初始化虚拟机对象,参数 2是虚拟机指令流 opcode。 ■ vm_init 分析
*(_QWORD *)v10 = v11; v9 = v12; v6 = (unsigned __int64)v12 * (unsigned __int128)4ui64; ... *(_QWORD *)(v10 + 8) = AllocMem(v6, *((_QWORD *)&v6 + 1)); *(_DWORD *)(v10 + 20) = 0; *(_DWORD *)(v10 + 16) = 0; *(_DWORD *)(v10 + 44) = 0; *(_DWORD *)(v10 + 40) = 0; *(_DWORD *)(v10 + 36) = 0; *(_DWORD *)(v10 + 32) = 0; *(_DWORD *)(v10 + 28) = 0; *(_DWORD *)(v10 + 24) = 0; *(_DWORD *)(v10 + 64) = 0; *(_DWORD *)(v10 + 48) = 0; *(_QWORD *)(v10 + 56) = v13; return v10;
部 分 函 数 根 据 上 下 文 分 析 已 重 定 义 名 字 , 方 便 后 续 分 析 。 textcolor{green}{部分函数根据上下文分析已重定义名字,方便后续分析。} 部分函数根据上下文分析已重定义名字,方便后续分析。
@line1: v11是上层函数传进来的 opcode。@line2 v 12 = 4096 textcolor{orange}{v12 = 4096} v12=4096。@line5: 分配内存,这里可以理解为虚拟机的中的堆栈。@line6到 @line15是虚拟机的寄存器,具体定义未知。@line16: v13就是上层函数传进来的那 3个输入数据。
对 v m _ i n i t textcolor{cornflowerblue}{vm_init} vm_init的分析大致知道虚拟机的结构成员数量是 14及其内存位置,但要了解清楚成员的具体含义还需要通过后续对调度器的分析。
■ vm_dispatcher 分析主体框架是个 switch结构,v35就是当前的操作码 op ,当 o p = 255 textcolor{orange}{op =255} op=255时退出虚拟机。并且知道了虚拟机其中一个寄存器是 PC,偏移 +20。当前目标是了解虚拟机的具体结构以及成员含义才能方便后续的分析。在通览整个调度器时,发现一处虚拟机处理 handler是内存到寄存器的操作
s u b _ 14007 E 600 textcolor{cornflowerblue}{sub_14007E600} sub_14007E600:
--*(_DWORD *)(v6 + 16);
if ( v7 == 1 )
*(_DWORD *)(v6 + 24) = *(_DWORD *)(*(_QWORD *)(v6 + 8) + 4i64 * *(unsigned int *)(v6 + 16));
if ( v7 == 2 )
*(_DWORD *)(v6 + 28) = *(_DWORD *)(*(_QWORD *)(v6 + 8) + 4i64 * *(unsigned int *)(v6 + 16));
if ( v7 == 3 )
*(_DWORD *)(v6 + 32) = *(_DWORD *)(*(_QWORD *)(v6 + 8) + 4i64 * *(unsigned int *)(v6 + 16));
if ( v7 == 4 )
*(_DWORD *)(v6 + 36) = *(_DWORD *)(*(_QWORD *)(v6 + 8) + 4i64 * *(unsigned int *)(v6 + 16));
if ( v7 == 5 )
*(_DWORD *)(v6 + 40) = *(_DWORD *)(*(_QWORD *)(v6 + 8) + 4i64 * *(unsigned int *)(v6 + 16));
if ( v7 == 6 )
*(_DWORD *)(v6 + 44) = *(_DWORD *)(*(_QWORD *)(v6 + 8) + 4i64 * *(unsigned int *)(v6 + 16));
联系 v m _ i n i t textcolor{cornflowerblue}{vm_init} vm_init的分析,可以知道这里是从内存中读取数据到寄存器,共有 6个通用寄存器(编号1~6)和一个堆栈指针 sp。目前还剩 3个成员的含义没有明确。
后续找到一个 handler类似于条件转移的操作
s u b _ 14007 E 240 textcolor{cornflowerblue}{sub_14007E240} sub_14007E240:
if ( *(_DWORD *)(v6 + 48) )
{
result = v6;
*(_DWORD *)(v6 + 20) = v7;//pc = v7
}
else
{
result = (unsigned int)(*(_DWORD *)(v6 + 20) + 5);
*(_DWORD *)(v6 + 20) = result; //pc = pc + 5
}
判断 v m + 48 textcolor{orange}{vm+48} vm+48 位置的值,不为 0则修改 pc的值为上层函数传来的跳转地址 v7,为 0则设置 p c = p c + 5 textcolor{orange}{pc = pc+5} pc=pc+5 ,表示继续执行。因此推断出 +48 的偏移是标志寄存器 flag。
目前还剩下 2个成员含义未知,并且在后续的观察中发现这 2个寄存器没有什么特别重要的用途,于是到此为止,可以分析出 vm的结构体如下:
typedef struct _vm {
uint8_t* opcode;
uint32_t* mem;
uint32_t reg_sp;
uint32_t pc;
uint32_t reg_1;
uint32_t reg_2;
uint32_t reg_3;
uint32_t reg_4;
uint32_t reg_5;
uint32_t reg_6;
uint32_t flag;
uint32_t reg_unk1;
uint32_t* data;
uint32_t reg_unk2;
}vm,*vm_ref;
接下来的目标就是把每个 handler的作用都分析清楚,对应的操作码 op是什么,方法是结合 vm结构体跟进函数去看看涉及到什么操作。最后分析出来的 op和 handler的对应关系如下表所示:
| 操作码OP | 操作Handler | 功能 |
|---|---|---|
| 0 | mov_reg_mem(vm,mem_id,reg_id) | 读取堆栈中mem_id位置处的4字节数据到reg_id表示的寄存器中 |
| 1 | mov_current_mem_value(vm,v) | 将立即数v存储到堆栈mem[vm->reg_sp]中,vm->reg_sp+=1 |
| 2 | mov_reg_current_mem(vm,reg_id) | vm->reg_sp-=1,当且仅当 reg_id >0 时,读取堆栈mem[vm->reg_sp] 4字节数据到reg_id表示的寄存器中,并返回mem[vm->reg_sp] 4字节数据 |
| 3 | my_call(vm,addr) | 保存pc、通用寄存器和flag的值到堆栈中,设置vm->pc = addr |
| 4 | my_ret(vm) | 从堆栈中恢复flag、通用寄存器和pc的值 |
| 5 | jmp(vm,addr) | 设置vm->pc = addr |
| 6 | jnz(vm,addr) | 判断vm->flag > 0,则设置vm->pc = addr,否则vm->pc += 5 |
| 7 | not_flag(vm) | vm->flag 逻辑取反 |
| 8 | add_reg1_reg2(vm,reg_id1,reg_id2) | 求和reg_id1和reg_id2所表示的寄存器的值,结果存到reg_id1表示的寄存器中 |
| 9 | sub_reg1_reg2(vm,reg_id1,reg_id2) | reg_id1和reg_id2所表示的寄存器的值相减,结果存到reg_id1表示的寄存器中 |
| 10 | mul_reg1_reg2(vm,reg_id1,reg_id2) | reg_id1和reg_id2所表示的寄存器的值相乘,结果存到reg_id1表示的寄存器中 |
| 11 | div_reg1_reg2(vm,reg_id1,reg_id2) | reg_id1和reg_id2所表示的寄存器的值相除,结果存到reg_id1表示的寄存器中 |
| 12 | xor_reg1_reg2(vm,reg_id1,reg_id2) | reg_id1和reg_id2所表示的寄存器的值相异或,结果存到reg_id1表示的寄存器中 |
| 13 | mov_current_mem_reg(vm,reg_id) | 读取reg_id所表示的寄存器数据到mem[vm->reg_sp],vm->reg_sp+=1 |
| 14 | cmp_reg1_reg2(vm,reg_id1,reg_id2) | 比较reg_id1和reg_id2所表示的寄存器数据,相等则设置vm->flag = 1,否则 vm->flag = 0 |
| 15 | and_reg1_reg2(vm,reg_id1,reg_id2) | reg_id1和reg_id2所表示的寄存器的值相与,结果存到reg_id1表示的寄存器中 |
| 16 | or_reg1_reg2(vm,reg_id1,reg_id2) | reg_id1和reg_id2所表示的寄存器的值相或,结果存到reg_id1表示的寄存器中 |
| 17 | ror_reg1_reg2(vm,reg_id1,reg_id2) | reg_id1表示的寄存器数据循环右移reg_id2所表示寄存器的数值个位 |
| 18 | rol_reg1_reg2(vm,reg_id1,reg_id2) | reg_id1表示的寄存器数据循环左移reg_id2所表示寄存器的数值个位 |
| 19 | not_reg(vm,reg_id) | 取反reg_id表示寄存器的数据 |
| 20 | mod_reg1_reg2(vm,reg_id1,reg_id2) | reg_id1和reg_id2所表示的寄存器的值进行模运算,结果存到reg_id1表示的寄存器中 |
| 208 | mov_mem_data(vm,v) | vm->mem[vm->reg_sp] = vm->data[v],vm->reg_sp+=1 |
| 224 | mov_mem_reg(vm,mem_id,reg_id) | 读取reg_id表示的寄存器的数据到vm->mem[vm->reg_sp-mem_id] |
| 240 | mov_mem_value(vm,mem_id,v) | vm->mem[vm->reg_sp-mem_id] = v |
给了opcode,如何知道 opcode指示 vm对输入的数据进行了哪些操作?如果手动单步跟踪,就是单纯的体力活,我采用的方法是重构这个 vm,并加入打印功能,打印每个操作中数据的转移和运算。
重 构 的 代 码 和 解 密 代 码 都 放 到 了 一 起 , 在 文 末 。 textcolor{green}{重构的代码和解密代码都放到了一起,在文末。} 重构的代码和解密代码都放到了一起,在文末。
■ log 分析打印出来的日志数据:
pc: 0x0 data[0] -> mem[0] pc: 0x5 mem[0]->reg_1 pc: 0x7 reg_1-> mem[0] pc: 0x9 mem[0]->reg_4 pc: 0xb 0x10 -> mem[0] pc: 0x10 mem[0]->reg_1 pc: 0x12 0x0 -> mem[0] pc: 0x17 mem[0]->reg_3 pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0xf -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0xc85f5c22 -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x0 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0xe -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0x5668259b -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0xd -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0x32e7328f -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0xc -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0x55abb385 -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0xb -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0x336ae593 -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0xa -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0xa899208a -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0x9 -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0x8d1368ec -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0x8 -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0xdaed429a -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0x7 -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0xf341d8f4 -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0x6 -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0x6d76a14d -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0x5 -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0x44da3b23 -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0x4 -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0x8d5f9534 -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0x3 -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0xf4cbd01d -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0x2 -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0xd28a7866 -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0x1 -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0xcf787563 -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 1 pc: 0x19 Jnz-1: 0x19->pc pc: 0x19 0x1 -> mem[0] pc: 0x1e mem[0]->reg_2 pc: 0x20 reg_1 - reg_2 pc: 0x23 reg_1-> mem[0] pc: 0x25 mem[0]->reg_5 pc: 0x27 0x8 -> mem[0] pc: 0x2c mem[0]->reg_6 pc: 0x2e reg_5 mod reg_6 pc: 0x31 reg_4 >> reg_5 pc: 0x34 0x9e3779b9 -> mem[0] pc: 0x39 mem[0]->reg_5 pc: 0x3b reg_4 ^ reg_5 pc: 0x3e reg_4-> mem[0] pc: 0x40 pc: 0x40 0x45 -> mem[1] pc: 0x40 0x0 -> mem[2] pc: 0x40 0x1 -> mem[3] pc: 0x40 0x0 -> mem[4] pc: 0x40 0x402a214a -> mem[5] pc: 0x40 0x9e3779b9 -> mem[6] pc: 0x40 0x8 -> mem[7] pc: 0x40 0x1 -> mem[8] Call: 0xad->pc pc: 0xad mem[1]->reg_1 pc: 0xb3 0x3 -> mem[9] pc: 0xb8 mem[9]->reg_2 pc: 0xba reg_1 + reg_2 pc: 0xbd reg_1->mem[1] pc: 0xc3 mem[0]->reg_2 pc: 0xc9 0x6 -> mem[9] pc: 0xce mem[9]->reg_3 pc: 0xd0 reg_2 << reg_3 pc: 0xd3 reg_2->mem[0] pc: 0xd9 mem[8]->flag mem[7]->reg_6 mem[6]->reg_5 mem[5]->reg_4 mem[4]->reg_3 mem[3]->reg_2 mem[2]->reg_1 mem[1]->pc Leave: 0x48->pc pc: 0x48 mem[0]->reg_4 pc: 0x4a reg_1 == reg_3? pc: 0x4d not_flag: 0 pc: 0x53 Jnz-0: 0x53->pc pc: 0x53 data[1] -> mem[0] pc: 0x58 data[2] -> mem[1] pc: 0x5d mem[1]->reg_2 pc: 0x5f mem[0]->reg_3 pc: 0x61 reg_4-> mem[0] pc: 0x63 mem[0]->reg_5 pc: 0x65 reg_5 | reg_2 pc: 0x68 reg_5 | reg_3 pc: 0x6b reg_5-> mem[0] pc: 0x6d reg_4-> mem[1] pc: 0x6f mem[1]->reg_5 pc: 0x71 reg_5 & reg_2 pc: 0x74 reg_5 & reg_3 pc: 0x77 reg_5-> mem[1] pc: 0x79 reg_4-> mem[2] pc: 0x7b mem[2]->reg_5 pc: 0x7d reg_5 & reg_2 pc: 0x80 reg_5-> mem[2] pc: 0x82 reg_4-> mem[3] pc: 0x84 mem[3]->reg_5 pc: 0x86 reg_5 & reg_3 pc: 0x89 reg_5-> mem[3] pc: 0x8b reg_2-> mem[4] pc: 0x8d mem[4]->reg_5 pc: 0x8f reg_5 & reg_3 pc: 0x92 mem[3]->reg_6 pc: 0x94 reg_5 ^ reg_6 pc: 0x97 mem[2]->reg_6 pc: 0x99 reg_5 ^ reg_6 pc: 0x9c mem[1]->reg_6 pc: 0x9e reg_5 ^ reg_6 pc: 0xa1 mem[0]->reg_6 pc: 0xa3 reg_5 ^ reg_6 pc: 0xa6 reg_5-> mem[0] pc: 0xa8 mem[0]->reg_1 pc: 0xaa ~reg_1
仔细在这份日志中做标记,逐个分析就会发现规律。reg_1作为最后 vm的结果返回到上层函数。最后还原得到 vm的算法
uint32_t vm_simplify(uint32_t* d) {
uint32_t a = d[0];
for (int i = 0; i < 16; i++) {
a = __ROR4__(a, (0xf - i) % 8) ^ 0x9e3779b9;
a = __ROL4__(a, 6);
}
return ~(((((d[2] & d[1]) ^ (a & d[1])) ^ (a & d[2])) ^ ((a & d[2]) & d[1])) ^ ((a | d[2]) | d[1]));
}
4. 逆算法分析
解决虚拟机算法是解决这道题的关键,在上面分析出来的算法中,循环部分的逆算法比较简单,难点在于 return语句的逻辑表达式,看上去比较复杂,现在尝试进行化简。
初步化简得
~( (d[2] & d[1]) ^ (a & d[2]) ^ (a & d[1] & d[2]) ^ (a | d[1] | d[2]) )
然后没有头绪了。。。一位朋友说 matlab可以进行化简,然后给他试了一下,结果是
等价于
~(a ^ d[1] ^ d[2])
这下子 vm的逆算法就很容易写出来了
uint32_t re_vm_simplify(uint32_t v1, uint32_t v2, uint32_t v3) {
uint32_t t = ~v1;
t = t ^ v2 ^ v3;
for (int i = 15; i > -1; i--) {
t = __ROR4__(t, 6);
t ^= 0x9e3779b9;
t = __ROL4__(t, (15 - i) % 8);
}
return t;
}
5. 求解分析
现在已经知道了正确的 re_hex_buf_md5和 正确的 vm结果,不妨记为 vm_ans。 还剩两个未知的 vm输入 re_hex_buf和 re_table_md5,根据之前对 G e n e r a t e _ T a b l e textcolor{cornflowerblue}{Generate_Table} Generate_Table的分析,虽然我们不知道 re_hex_buf的正确数据,但是 table只有 100种可能,所以他的 md5值也只有 100种可能,只要枚举这一百种可能和正确的 re_hex_buf_md5作为 vm的输入,反求出 re_hex_buf,再对 re_hex_buf求 MD5,结果和正确的 re_hex_buf_md5对比,从而找到正确的 flag。
0x02 求解代码u n i t . h textcolor{orange}{unit.h} unit.h
#pragma once #includetypedef struct _vm { uint8_t* opcode; uint32_t* mem; uint32_t reg_sp; uint32_t pc; uint32_t reg_1; uint32_t reg_2; uint32_t reg_3; uint32_t reg_4; uint32_t reg_5; uint32_t reg_6; uint32_t flag; uint32_t reg_unk1; uint32_t* data; uint32_t reg_unk2; }vm,*vm_ref; vm_ref vm_init(uint8_t* opcode, uint32_t* dat); uint32_t reverse_bytes(uint32_t* v); uint32_t* get_reg_from_id(vm_ref vm_entry, uint32_t reg_id); void vm_dispatcher(vm_ref vm_entry); void mov_current_mem_value(vm_ref vm_entry, uint32_t reg_id); void mov_mem_value(vm_ref vm_entry, uint32_t mem_id, uint32_t v); uint32_t mov_reg_current_mem(vm_ref vm_entry, uint32_t reg_id); void my_call(vm_ref vm_entry, uint32_t addr); void my_ret(vm_ref vm_entry); void jmp(vm_ref vm_entry, uint32_t addr); void jnz(vm_ref vm_entry, uint32_t addr); void not_flag(vm_ref vm_entry); void add_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2); void sub_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2); void mul_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2); void div_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2); void xor_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2); void cmp_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2); void and_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2); void or_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2); void ror_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2); void rol_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2); void mod_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2); void not_reg(vm_ref vm_entry, uint32_t reg_id); void mov_mem_data(vm_ref vm_entry, uint32_t data_id); void mov_mem_reg(vm_ref vm_entry, uint32_t mem_id,uint32_t reg_id); void mov_current_mem_reg(vm_ref vm_entry, uint32_t reg_id1); void mov_mem_value(vm_ref vm_entry, uint32_t mem_id, uint32_t v); void mov_reg_mem(vm_ref vm_entry, uint32_t mem_id, uint32_t reg_id); uint32_t vm_simplify(uint32_t* d); void get_md5(uint8_t* src, size_t size, uint8_t* out); uint32_t re_vm_simplify(uint32_t v1, uint32_t v2, uint32_t v3); void generate_table(uint8_t v,uint8_t* out);
b a b y _ r e . c p p textcolor{orange}{baby_re.cpp} baby_re.cpp:
#include0x03 参考#include #include"unit.h" #include"defs.h" uint8_t g_opcode[224] = {0xd0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0xd, 0x1, 0x2, 0x4, 0x1, 0x10, 0x0, 0x0, 0x0, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0x1, 0x1, 0x0, 0x0, 0x0, 0x2, 0x2, 0x9, 0x1, 0x2, 0xd, 0x1, 0x2, 0x5, 0x1, 0x8, 0x0, 0x0, 0x0, 0x2, 0x6, 0x14, 0x5, 0x6, 0x11, 0x4, 0x5, 0x1, 0xb9, 0x79, 0x37, 0x9e, 0x2, 0x5, 0xc, 0x4, 0x5, 0xd, 0x4, 0x3, 0xad, 0x0, 0x0, 0x0, 0xc, 0x4, 0x1, 0x2, 0x4, 0xe, 0x1, 0x3, 0x7, 0x6, 0x19, 0x0, 0x0, 0x0, 0xd0, 0x1, 0x0, 0x0, 0x0, 0xd0, 0x2, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x3, 0xd, 0x4, 0x2, 0x5, 0x10, 0x5, 0x2, 0x10, 0x5, 0x3, 0xd, 0x5, 0xd, 0x4, 0x2, 0x5, 0xf, 0x5, 0x2, 0xf, 0x5, 0x3, 0xd, 0x5, 0xd, 0x4, 0x2, 0x5, 0xf, 0x5, 0x2, 0xd, 0x5, 0xd, 0x4, 0x2, 0x5, 0xf, 0x5, 0x3, 0xd, 0x5, 0xd, 0x2, 0x2, 0x5, 0xf, 0x5, 0x3, 0x2, 0x6, 0xc, 0x5, 0x6, 0x2, 0x6, 0xc, 0x5, 0x6, 0x2, 0x6, 0xc, 0x5, 0x6, 0x2, 0x6, 0xc, 0x5, 0x6, 0xd, 0x5, 0x2, 0x1, 0x13, 0x1, 0xff, 0x0, 0x8, 0x0, 0x0, 0x0, 0x1, 0x1, 0x3, 0x0, 0x0, 0x0, 0x2, 0x2, 0x8, 0x1, 0x2, 0xe0, 0x8, 0x0, 0x0, 0x0, 0x1, 0x0, 0x9, 0x0, 0x0, 0x0, 0x2, 0x1, 0x6, 0x0, 0x0, 0x0, 0x2, 0x3, 0x12, 0x2, 0x3, 0xe0, 0x9, 0x0, 0x0, 0x0, 0x2, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; vm_ref vm_init(uint8_t* opcode,uint32_t* dat) { vm_ref vm_entry = nullptr; vm_entry = new vm; if (vm_entry == nullptr) { std::cout << "vm_init():vm_entry == nullptr" << std::endl; exit(-1); } memset(vm_entry,0, sizeof(vm)); vm_entry->mem = new uint32_t[4096]; if (vm_entry->mem == nullptr) { std::cout << "vm_init():vm_entry->mem == nullptr" << std::endl; exit(-1); } vm_entry->data = dat; vm_entry->opcode = opcode; } void vm_dispatcher(vm_ref vm_entry) { uint8_t op = 0xff; uint8_t pc = 0; uint8_t* opc = nullptr; opc = vm_entry->opcode; while (1) { op = vm_entry->opcode[vm_entry->pc]; if(op==0xFF) break; pc = vm_entry->pc; switch (op) { case 0: { mov_reg_mem(vm_entry, *(uint32_t*)&opc[pc + 1], opc[pc + 5]); vm_entry->pc += 6; break; } case 1: { mov_current_mem_value(vm_entry, *(uint32_t*)&opc[pc + 1]); vm_entry->pc += 5; break; } case 2: { mov_reg_current_mem(vm_entry, opc[pc + 1]); vm_entry->pc += 2; break; } case 3: { my_call(vm_entry, *(uint32_t*)&opc[pc + 1]); break; } case 4: { my_ret(vm_entry); break; } case 5: { jmp(vm_entry, *(uint32_t*)&opc[pc + 1]); break; } case 6: { jnz(vm_entry, *(uint32_t*)&opc[pc + 1]); break; } case 7: { not_flag(vm_entry); vm_entry->pc += 1; break; } case 8: { add_reg1_reg2(vm_entry, opc[pc + 1], opc[pc + 2]); vm_entry->pc += 3; break; } case 9: { sub_reg1_reg2(vm_entry, opc[pc + 1], opc[pc + 2]); vm_entry->pc += 3; break; } case 10: { mul_reg1_reg2(vm_entry, opc[pc + 1], opc[pc + 2]); vm_entry->pc += 3; break; } case 11: { div_reg1_reg2(vm_entry, opc[pc + 1], opc[pc + 2]); vm_entry->pc += 3; break; } case 12: { xor_reg1_reg2(vm_entry, opc[pc + 1], opc[pc + 2]); vm_entry->pc += 3; break; } case 13: { mov_current_mem_reg(vm_entry, opc[pc + 1]); vm_entry->pc += 2; break; } case 14: { cmp_reg1_reg2(vm_entry, opc[pc + 1], opc[pc + 2]); vm_entry->pc += 3; break; } case 15: { and_reg1_reg2(vm_entry, opc[pc + 1], opc[pc + 2]); vm_entry->pc += 3; break; } case 16: { or_reg1_reg2(vm_entry, opc[pc + 1], opc[pc + 2]); vm_entry->pc += 3; break; } case 17: { ror_reg1_reg2(vm_entry, opc[pc + 1], opc[pc + 2]); vm_entry->pc += 3; break; } case 18: { rol_reg1_reg2(vm_entry, opc[pc + 1], opc[pc + 2]); vm_entry->pc += 3; break; } case 19: { not_reg(vm_entry, opc[pc + 1]); vm_entry->pc += 2; break; } case 20: { mod_reg1_reg2(vm_entry, opc[pc + 1], opc[pc + 2]); vm_entry->pc += 3; break; } case 0xD0: { mov_mem_data(vm_entry, *(uint32_t*)&opc[pc + 1]); vm_entry->pc += 5; break; } case 0xE0: { mov_mem_reg(vm_entry, *(uint32_t*)&opc[pc + 1], opc[pc + 5]); vm_entry->pc += 6; break; } case 0xF0: { mov_mem_value(vm_entry, *(uint32_t*)&opc[pc + 1], *(uint32_t*)&opc[pc + 5]); vm_entry->pc += 9; break; } default: continue; } } } uint32_t vm_simplify(uint32_t* d) { uint32_t a = d[0]; for (int i = 0; i < 16; i++) { a = __ROR4__(a, (0xf - i) % 8) ^ 0x9e3779b9; a = __ROL4__(a, 6); } return ~(((((d[2] & d[1]) ^ (a & d[1])) ^ (a & d[2])) ^ ((a & d[2]) & d[1])) ^ ((a | d[2]) | d[1])); } uint32_t re_vm_simplify(uint32_t v1, uint32_t v2, uint32_t v3) { uint32_t t = ~v1; t = t ^ v2 ^ v3; for (int i = 15; i > -1; i--) { t = __ROR4__(t, 6); t ^= 0x9e3779b9; t = __ROL4__(t, (15 - i) % 8); } return t; } uint32_t reverse_bytes(uint32_t* v) { return (*((uint8_t*)v + 3) << 24) | (*((uint8_t*)v + 2) << 16) | (uint32_t)*v; } void get_md5(uint8_t* src, size_t size, uint8_t* out) { HCRYPTPROV hProv; if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { return ; } HCRYPTHASH hHash; if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) { CryptReleaseContext(hProv, 0); return ; } if (!CryptHashData(hHash, src, size, 0)) { CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); return ; } DWORD dwSize; DWORD dwLen = sizeof(dwSize); CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)(&dwSize), &dwLen, 0); BYTE* pHash = new BYTE[dwSize]; dwLen = dwSize; CryptGetHashParam(hHash, HP_HASHVAL, pHash, &dwLen, 0); for (DWORD i = 0; i < dwLen; i++) { out[i] = pHash[i]; } delete[] pHash; CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); return ; } void generate_table(uint8_t v, uint8_t* out) { uint8_t a = 0,r=v; for (int i = 0; i < 100; i++) { a = 0; r = r ^ 0xc3; out[i] = r; for (int j = 0; j < 8; j++) a = a ^ ((r >> j) & 1); r = a + (2 * r); } } int main() { uint32_t t = 0; uint32_t vm_ans[4] = {0x1F7902CC, 0x2FAE3D15, 0xCEEBFE91, 0xAFF6AF42 }; uint32_t d[3] = { 0x3412CDAB ,0xC2BD227E ,0xBC633F6E }; uint32_t flag_md5[4] = { 0xC5D83690 ,0x978162EA ,0x1932A96C ,0x4222669 }; uint8_t tab[100] = {0}; uint8_t h_t[16] = { 0 }; uint8_t input[16] = {0}; uint8_t input_md5[16] = { 0 }; bool bIsFound = true; for (int i = 0; i < 100; i++) { bIsFound = true; generate_table(i, tab); get_md5(tab, 100, h_t); for (int j = 0; j < 4; j++) { t = re_vm_simplify(vm_ans[j], reverse_bytes(&((uint32_t*)h_t)[j]), flag_md5[j]); t = reverse_bytes(&t); ((uint32_t*)input)[j] = t; } get_md5(input, 16, input_md5); for (int k = 0; k < 4; k++) { if (((uint32_t*)input_md5)[k] != flag_md5[k]) { bIsFound = false; break; } } if (bIsFound) { printf("flag{"); for (int c = 0; c < 16; c++) { if (c==4 || c==6 || c==8 || c ==10) { printf("-%02x", input[c]); } else { printf("%02x", input[c]); } } printf("}n"); break; } } //flag{9e573902-0e31-4837-a337-32a475ca007c} system("pause"); return 0; } uint32_t* get_reg_from_id(vm_ref vm_entry, uint32_t reg_id) { switch (reg_id) { case 1: return &vm_entry->reg_1; case 2: return &vm_entry->reg_2; case 3: return &vm_entry->reg_3; case 4: return &vm_entry->reg_4; case 5: return &vm_entry->reg_5; case 6: return &vm_entry->reg_6; default: return nullptr; } } void mov_reg_mem(vm_ref vm_entry, uint32_t mem_id,uint32_t reg_id) { uint32_t* reg = get_reg_from_id(vm_entry, reg_id); *reg = vm_entry->mem[vm_entry->reg_sp - mem_id]; printf("pc: 0x%x mem[%u]->reg_%dn", vm_entry->pc, vm_entry->reg_sp - mem_id,reg_id ); } void mov_current_mem_value(vm_ref vm_entry, uint32_t v) { vm_entry->mem[vm_entry->reg_sp]=v; printf("pc: 0x%x 0x%x -> mem[%d]n", vm_entry->pc, v, vm_entry->reg_sp); vm_entry->reg_sp += 1; } uint32_t mov_reg_current_mem(vm_ref vm_entry, uint32_t reg_id) { uint32_t* reg = get_reg_from_id(vm_entry, reg_id); if (!vm_entry->reg_sp)return -1; vm_entry->reg_sp -= 1; if (reg == nullptr)return vm_entry->mem[vm_entry->reg_sp]; *reg = vm_entry->mem[vm_entry->reg_sp]; printf("pc: 0x%x mem[%u]->reg_%dn", vm_entry->pc,vm_entry->reg_sp,reg_id); } void my_call(vm_ref vm_entry, uint32_t addr) { printf("pc: 0x%xn", vm_entry->pc); mov_current_mem_value(vm_entry, vm_entry->pc + 5); mov_current_mem_value(vm_entry, vm_entry->reg_1); mov_current_mem_value(vm_entry, vm_entry->reg_2); mov_current_mem_value(vm_entry, vm_entry->reg_3); mov_current_mem_value(vm_entry, vm_entry->reg_4); mov_current_mem_value(vm_entry, vm_entry->reg_5); mov_current_mem_value(vm_entry, vm_entry->reg_6); mov_current_mem_value(vm_entry, vm_entry->flag); vm_entry->pc = addr; printf("Call: 0x%x->pcnn", addr); } void my_ret(vm_ref vm_entry) { printf("pc: 0x%xn", vm_entry->pc); vm_entry->flag = mov_reg_current_mem(vm_entry, 0); printf("mem[%d]->flagn", vm_entry->reg_sp); vm_entry->reg_6= mov_reg_current_mem(vm_entry, 0); printf("mem[%d]->reg_6n", vm_entry->reg_sp); vm_entry->reg_5= mov_reg_current_mem(vm_entry, 0); printf("mem[%d]->reg_5n", vm_entry->reg_sp); vm_entry->reg_4= mov_reg_current_mem(vm_entry, 0); printf("mem[%d]->reg_4n", vm_entry->reg_sp); vm_entry->reg_3= mov_reg_current_mem(vm_entry, 0); printf("mem[%d]->reg_3n", vm_entry->reg_sp); vm_entry->reg_2= mov_reg_current_mem(vm_entry, 0); printf("mem[%d]->reg_2n", vm_entry->reg_sp); vm_entry->reg_1= mov_reg_current_mem(vm_entry, 0); printf("mem[%d]->reg_1n", vm_entry->reg_sp); vm_entry->pc= mov_reg_current_mem(vm_entry, 0); printf("mem[%d]->pcn", vm_entry->reg_sp); printf("Leave: 0x%x->pcnn", vm_entry->pc); } void jmp(vm_ref vm_entry, uint32_t addr) { vm_entry->pc = addr; printf("pc: 0x%x Jmp: 0x%x->pcn", vm_entry->pc,vm_entry->pc); } void jnz(vm_ref vm_entry, uint32_t addr) { if (vm_entry->flag) { vm_entry->pc = addr; printf("pc: 0x%x Jnz-1: 0x%x->pcn", vm_entry->pc,vm_entry->pc); } else { vm_entry->pc = vm_entry->pc + 5; printf("pc: 0x%x Jnz-0: 0x%x->pcn", vm_entry->pc,vm_entry->pc); } } void not_flag(vm_ref vm_entry) { if (vm_entry->flag == 1) vm_entry->flag = 0; else vm_entry->flag = 1; printf("pc: 0x%x not_flag: %dn", vm_entry->pc,vm_entry->flag); } void add_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2) { uint32_t* reg1=get_reg_from_id(vm_entry,reg_id1); uint32_t* reg2=get_reg_from_id(vm_entry,reg_id2); *reg1 = *reg1 + *reg2; printf("pc: 0x%x reg_%d + reg_%dn", vm_entry->pc,reg_id1,reg_id2); } void sub_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2) { uint32_t* reg1 = get_reg_from_id(vm_entry, reg_id1); uint32_t* reg2 = get_reg_from_id(vm_entry, reg_id2); *reg1 = *reg1 - *reg2; printf("pc: 0x%x reg_%d - reg_%dn", vm_entry->pc,reg_id1, reg_id2); } void mul_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2) { uint32_t* reg1 = get_reg_from_id(vm_entry, reg_id1); uint32_t* reg2 = get_reg_from_id(vm_entry, reg_id2); *reg1 = *reg1 * *reg2; printf("pc: 0x%x reg_%d * reg_%dn", vm_entry->pc,reg_id1, reg_id2); } void div_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2) { uint32_t* reg1 = get_reg_from_id(vm_entry, reg_id1); uint32_t* reg2 = get_reg_from_id(vm_entry, reg_id2); *reg1 = *reg1 / *reg2; printf("pc: 0x%x reg_%d / reg_%dn", vm_entry->pc, reg_id1, reg_id2); } void xor_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2) { uint32_t* reg1 = get_reg_from_id(vm_entry, reg_id1); uint32_t* reg2 = get_reg_from_id(vm_entry, reg_id2); *reg1 = *reg1 ^ *reg2; printf("pc: 0x%x reg_%d ^ reg_%dn", vm_entry->pc, reg_id1, reg_id2); } void cmp_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2) { uint32_t* reg1 = get_reg_from_id(vm_entry, reg_id1); uint32_t* reg2 = get_reg_from_id(vm_entry, reg_id2); if (*reg1 == *reg2) vm_entry->flag = 1; else vm_entry->flag = 0; printf("pc: 0x%x reg_%d == reg_%d?n", vm_entry->pc,reg_id1, reg_id2); } void and_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2) { uint32_t* reg1 = get_reg_from_id(vm_entry, reg_id1); uint32_t* reg2 = get_reg_from_id(vm_entry, reg_id2); *reg1 = *reg1 & *reg2; printf("pc: 0x%x reg_%d & reg_%dn", vm_entry->pc, reg_id1, reg_id2); } void or_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2) { uint32_t* reg1 = get_reg_from_id(vm_entry, reg_id1); uint32_t* reg2 = get_reg_from_id(vm_entry, reg_id2); *reg1 = *reg1 | *reg2; printf("pc: 0x%x reg_%d | reg_%dn", vm_entry->pc, reg_id1, reg_id2); } void ror_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2) { uint32_t* reg1 = get_reg_from_id(vm_entry, reg_id1); uint32_t* reg2 = get_reg_from_id(vm_entry, reg_id2); *reg1 = __ROR4__ (*reg1, *reg2); printf("pc: 0x%x reg_%d >> reg_%dn", vm_entry->pc,reg_id1, reg_id2); } void rol_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2) { uint32_t* reg1 = get_reg_from_id(vm_entry, reg_id1); uint32_t* reg2 = get_reg_from_id(vm_entry, reg_id2); *reg1 = __ROL4__(*reg1, *reg2); printf("pc: 0x%x reg_%d << reg_%dn", vm_entry->pc,reg_id1, reg_id2); } void mod_reg1_reg2(vm_ref vm_entry, uint32_t reg_id1, uint32_t reg_id2) { uint32_t* reg1 = get_reg_from_id(vm_entry, reg_id1); uint32_t* reg2 = get_reg_from_id(vm_entry, reg_id2); *reg1 = *reg1 % *reg2; printf("pc: 0x%x reg_%d mod reg_%dn", vm_entry->pc,reg_id1, reg_id2); } void not_reg(vm_ref vm_entry, uint32_t reg_id) { uint32_t* reg = get_reg_from_id(vm_entry, reg_id); *reg = ~*reg; printf("pc: 0x%x ~reg_%dn", vm_entry->pc,reg_id); } void mov_mem_data(vm_ref vm_entry, uint32_t data_id) { //mov_current_mem_value(vm_entry, vm_entry->data[data_id]); vm_entry->mem[vm_entry->reg_sp] = vm_entry->data[data_id]; printf("pc: 0x%x data[%d] -> mem[%d]n", vm_entry->pc, data_id, vm_entry->reg_sp); vm_entry->reg_sp += 1; } void mov_mem_reg(vm_ref vm_entry, uint32_t mem_id, uint32_t reg_id) { uint32_t* reg = get_reg_from_id(vm_entry, reg_id); vm_entry->mem[vm_entry->reg_sp - mem_id] = *reg; printf("pc: 0x%x reg_%d->mem[%d]n", vm_entry->pc,reg_id, vm_entry->reg_sp-mem_id); } void mov_current_mem_reg(vm_ref vm_entry, uint32_t reg_id1) { uint32_t* reg = get_reg_from_id(vm_entry, reg_id1); vm_entry->mem[vm_entry->reg_sp] = *reg; printf("pc: 0x%x reg_%d-> mem[%d]n", vm_entry->pc,reg_id1, vm_entry->reg_sp); vm_entry->reg_sp += 1; //mov_current_mem_value(vm_entry, *reg); } void mov_mem_value(vm_ref vm_entry, uint32_t mem_id, uint32_t v) { vm_entry->mem[vm_entry->reg_sp - mem_id] = v; printf("pc: 0x%x 0x%x -> mem[%d]n", vm_entry->pc,v, vm_entry->reg_sp - mem_id); }
[1] https://blog.csdn.net/Breeze_CAT/article/details/106373603?spm=1001.2014.3001.5502
[2] https://bbs.pediy.com/thread-259714.htm



