标签:lin 就是 0x13 结束 相等 ack man 比较 loading
vm的题目欠了好久了~~
首先OD打开,跟进去,发现此处每次CALL的位置都会变化。这应该就是我们要找的。
跟进这个函数,大概分析下流程,能找到虚拟机的字节码。
同时,在IDA里对应。可以找到CALL调用的函数的地址。通过X交叉引用,就能找到虚拟机的指令集。
List里存有各个opcode对应的地址,有了指令集。结合IDA和OD动调,逐个分析其功能。在看各函数功能的时候,同时要分辨出各个参数的作用。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
这里是字节码,在调用中用了两个数组。每次调用都取两个操作数,command_0是第一个,_1是第二个。
这里存放四个寄存器。
剩下的是所总结的其他的参数作用。有些参数实在是看不懂。。。
----------------------------------------------------------------------------------------------------------------------------------------
然后要分析指令集的功能。没有注释的就不上图了。??是看不懂的,也有很多标注不太标准。
0.eipadd
1.mov
2.VM_push_data
3.vm_push
4.vm_pop
5.caseprint
6.vm_add
7.vm_sub
8.vm_mul
9.vm_div
10.vm_xor
11.vm_jmp
12.vm_subcmp
13.vm_je
14.vm_jne
15.vm_big_jmp
16.vm_low_jmp
17.vm_input
18.???
19.vm_LoadStack
20.vm_LoadString
0xff: vm_end
---------------------------------------------------------------------------------------------------------------------------------------------------
然后就是写脚本翻译一下vm的字节码。
1 code =[ #字节码 2 0x01, 0x03, 0x03, 0x05, 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 3 0x01, 0x11, 0x0C, 0x00, 0x01, 0x0D, 0x0A, 0x00, 0x01, 0x03, 4 0x01, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x01, 0x02, 0x00, 5 0x01, 0x00, 0x11, 0x0C, 0x00, 0x02, 0x0D, 0x2B, 0x00, 0x14, 6 0x00, 0x02, 0x01, 0x01, 0x61, 0x0C, 0x00, 0x01, 0x10, 0x1A, 7 0x00, 0x01, 0x01, 0x7A, 0x0C, 0x00, 0x01, 0x0F, 0x1A, 0x00, 8 0x01, 0x01, 0x47, 0x0A, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 9 0x00, 0x01, 0x0B, 0x24, 0x00, 0x01, 0x01, 0x41, 0x0C, 0x00, 10 0x01, 0x10, 0x24, 0x00, 0x01, 0x01, 0x5A, 0x0C, 0x00, 0x01, 11 0x0F, 0x24, 0x00, 0x01, 0x01, 0x4B, 0x0A, 0x00, 0x01, 0x01, 12 0x01, 0x01, 0x07, 0x00, 0x01, 0x01, 0x01, 0x10, 0x09, 0x00, 13 0x01, 0x03, 0x01, 0x00, 0x03, 0x00, 0x00, 0x01, 0x01, 0x01, 14 0x06, 0x02, 0x01, 0x0B, 0x0B, 0x00, 0x02, 0x07, 0x00, 0x02, 15 0x0D, 0x00, 0x02, 0x00, 0x00, 0x02, 0x05, 0x00, 0x02, 0x01, 16 0x00, 0x02, 0x0C, 0x00, 0x02, 0x01, 0x00, 0x02, 0x00, 0x00, 17 0x02, 0x00, 0x00, 0x02, 0x0D, 0x00, 0x02, 0x05, 0x00, 0x02, 18 0x0F, 0x00, 0x02, 0x00, 0x00, 0x02, 0x09, 0x00, 0x02, 0x05, 19 0x00, 0x02, 0x0F, 0x00, 0x02, 0x03, 0x00, 0x02, 0x00, 0x00, 20 0x02, 0x02, 0x00, 0x02, 0x05, 0x00, 0x02, 0x03, 0x00, 0x02, 21 0x03, 0x00, 0x02, 0x01, 0x00, 0x02, 0x07, 0x00, 0x02, 0x07, 22 0x00, 0x02, 0x0B, 0x00, 0x02, 0x02, 0x00, 0x02, 0x01, 0x00, 23 0x02, 0x02, 0x00, 0x02, 0x07, 0x00, 0x02, 0x02, 0x00, 0x02, 24 0x0C, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x01, 0x02, 25 0x01, 0x13, 0x01, 0x02, 0x04, 0x00, 0x00, 0x0C, 0x00, 0x01, 26 0x0E, 0x5B, 0x00, 0x01, 0x01, 0x22, 0x0C, 0x02, 0x01, 0x0D, 27 0x59, 0x00, 0x01, 0x01, 0x01, 0x06, 0x02, 0x01, 0x0B, 0x4E, 28 0x00, 0x01, 0x03, 0x00, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00, 29 0x01, 0x03, 0x01, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 30 ] 31 opcodekey = {0:‘eipadd‘,1:‘mov‘,2:‘VM_push_data‘,3:‘vm_push‘,4:‘vm_pop‘,5:‘caseprint‘,6:‘vm_add‘, 32 7:‘vm_sub‘,8:‘vm_mul‘,9:‘vm_div‘,10:‘vm_xor‘,11:‘vm_jmp‘,12:‘vm_subcmp‘, 33 13:‘vm_je‘,14:‘vm_jne‘,15:‘vm_big_jmp‘,16:‘vm_low_jmp‘,17:‘vm_input‘,18:‘???‘, 34 19:‘vm_LoadStack‘,20:‘vm_LoadString‘,0XFF:‘vm_end‘} 35 num =0 36 line = 1; 37 for i in range(len(code)): 38 if(num==0): 39 print(str(line)+‘: ‘+opcodekey[code[i]],end=‘ ‘) 40 line = line +1 41 else: 42 print(code[i],end=‘ ‘) 43 if(num==2): 44 print() 45 num +=1 46 if(num==3): 47 num=0
分析一下所得到的伪代码。得到程序的基本流程。
1: mov 3 3 2: caseprint 0 0 3: vm_input 0 0 输入flag 4: mov 1 17 将17放到v1 5: vm_subcmp 0 1 v1-v0,比较长度 6: vm_je 10 0 相等则跳10 7: mov 3 1 8: caseprint 0 0 9: vm_end 0 0 结束 10: mov 2 0 0给v2 11: mov 0 17 17给v0 12: vm_subcmp 0 2 比较v0和v2 13: vm_je 43 0 相等则到43 ============================================ 14: vm_LoadString 0 2 15: mov 1 97 97给v1 16: vm_subcmp 0 1 v0和97比较 17: vm_low_jmp 26 0 小于则跳到26 18: mov 1 122 122给v1 19: vm_subcmp 0 1 比较 20: vm_big_jmp 26 0 大于则跳26 ===========若是小写字母====================== 21: mov 1 71 71给1 22: vm_xor 0 1 v0与v1异或,放在v0 23: mov 1 1 1给1 24: vm_add 0 1 v0++ 25: vm_jmp 36 0 跳到36 ============================================= 26: mov 1 65 65给v1 27: vm_subcmp 0 1 比较 28: vm_low_jmp 36 0 小于则跳36 29: mov 1 90 90给v1 30: vm_subcmp 0 1 比较 31: vm_big_jmp 36 0 大于则跳36 ===========若是大写字母========================== 32: mov 1 75 75给1 33: vm_xor 0 1 异或,放在v0 34: mov 1 1 35: vm_sub 0 1 v0-- ================================================== 36: mov 1 16 16给1 37: vm_div 0 1 v0/v1。就是加密后flag/16.结果在v0,余数在v1 38: vm_push 1 0 v1压栈,余数 39: vm_push 0 0 v0压栈,商 40: mov 1 1 1给v1 41: vm_add 2 1 v2+1,表示已经完成加密的Flag的个数 42: vm_jmp 11 0 跳到11 43: VM_push_data 7 0 数据压栈,第二位 44: VM_push_data 13 0 45: VM_push_data 0 0 46: VM_push_data 5 0 47: VM_push_data 1 0 48: VM_push_data 12 0 49: VM_push_data 1 0 50: VM_push_data 0 0 51: VM_push_data 0 0 52: VM_push_data 13 0 53: VM_push_data 5 0 54: VM_push_data 15 0 55: VM_push_data 0 0 56: VM_push_data 9 0 57: VM_push_data 5 0 58: VM_push_data 15 0 59: VM_push_data 3 0 60: VM_push_data 0 0 61: VM_push_data 2 0 62: VM_push_data 5 0 63: VM_push_data 3 0 64: VM_push_data 3 0 65: VM_push_data 1 0 66: VM_push_data 7 0 67: VM_push_data 7 0 68: VM_push_data 11 0 69: VM_push_data 2 0 70: VM_push_data 1 0 71: VM_push_data 2 0 72: VM_push_data 7 0 73: VM_push_data 2 0 74: VM_push_data 12 0 75: VM_push_data 2 0 76: VM_push_data 2 0 77: mov 2 1 1给v2(这里v2是数量) 78: vm_LoadStack 1 2 79: vm_pop 0 0 出栈,放到v0 80: vm_subcmp 0 1 v0和v1比较 81: vm_jne 91 0 不相等就到91 82: mov 1 34 34给v1 83: vm_subcmp 2 1 v2和v1比较 84: vm_je 89 0 相等就到89 85: mov 1 1 1给v1 86: vm_add 2 1 v2++ 87: vm_jmp 78 0 到78 ================成功================== 88: mov 3 0 89: caseprint 0 0 90: vm_end 0 0 ================结束================== 91: mov 3 1 92: caseprint 0 0 93: vm_end 0 0 94: eipadd
大体的流程是,输入17位Flag。对每一位,如果是小写,则(flag+1)^71,如果是大写,则(flag-1)^75。然后对每一位,除以16.商和余数分别压栈。再与已经在另一个栈中的数据分别比较,相同则正确。
编写解密脚本。
1 a=[7 2 ,13 3 ,0 4 ,5 5 ,1 6 ,12 7 ,1 8 ,0 9 ,0 10 ,13 11 ,5 12 ,15 13 ,0 14 ,9 15 ,5 16 ,15 17 ,3 18 ,0 19 ,2 20 ,5 21 ,3 22 ,3 23 ,1 24 ,7 25 ,7 26 ,11 27 ,2 28 ,1 29 ,2 30 ,7 31 ,2 32 ,12 33 ,2 34 ,2] 35 b=[0]*17 36 j=0 37 for i in range(0,len(a),2): 38 b[j]=a[i]*16+a[i+1] 39 j += 1 40 print(b) 41 t = 0 42 flag = ‘‘ 43 for i in range(len(b)): 44 t = (b[i]+1)^75 45 if t>=ord(‘A‘) and t<=ord(‘Z‘): 46 flag += chr(t) 47 continue 48 t = (b[i]-1)^71 49 if t>=ord(‘a‘) and t<=ord(‘z‘): 50 flag += chr(t) 51 continue 52 flag += chr(b[i]) 53 flag=flag[::-1] 54 print(flag)
flag{Such_A_EZVM}
标签:lin 就是 0x13 结束 相等 ack man 比较 loading
原文地址:https://www.cnblogs.com/EveningBreeze/p/13773930.html