标 题: 【原创】Themida 2260 虚拟机 FISH 初探(一)作 者: xiaohang时 间: 2016-03-03,00:39:37链 接: http://bbs.pediy.com/showthread.php?t=208207
// FISH Virtual Handler 0000 00422A0F00422A17 MOV DWORD PTR [EBP+0x53],0x000422A25 MOV DWORD PTR [EBP+0xa7],0x000422A33 MOV DWORD PTR [EBP+0x89],0x000422A41 MOV DWORD PTR [EBP+0x14],0x000422A4F MOV DWORD PTR [EBP+0x8f],0x000422A5D MOV WORD PTR [EBP+0xa0],0x000422A6A MOV BYTE PTR [EBP+0x57],0x000422A75 MOV DWORD PTR [EBP+0x68],0x000422A88 MOV ESI,DWORD PTR [EBP+0x8]00422A8A ADD ESI,0x000422A90 MOV DI,WORD PTR [ESI]00422A93 SHL EDI,0x200422A9E MOV ESI,DWORD PTR [EBP+0x4f]00422AA0 ADD ESI,EDI00422AA2 MOV EDX,DWORD PTR [ESI]00422AAB ADD DWORD PTR [EBP+0x8],0x200422AB1 JMP EDX
0041A677 MOV EBX,DWORD PTR [EBP+0x8] //读取opcode 指针0041A679 ADD EBX,0x9 //opcode指针加上偏移0041A67F MOVZX ECX,BYTE PTR [EBX] //读取BYTE 位的opcode ,这里我们暂且称之为参数A0041A682 OR DWORD PTR [EBP+0x8f],0x5df470f20041A690 ADD ECX,DWORD PTR [EBP+0x53]0041A69A ADD ECX,DWORD PTR [EBP+0xa7]0041A6A4 ADD ECX,DWORD PTR [EBP+0x68]0041A6AE OR DWORD PTR [EBP+0x53],ECX //利用读取的Opcode对加密寄存器再加密0041A6B8 OR DWORD PTR [EBP+0xa7],0x2a3b97830041A6C6 SUB ECX,DWORD PTR [EBP+0x89] //解密读取的Opcode 参数A0041A6D0 OR DWORD PTR [EBP+0x89],0x5570350f0041A6DE SUB BYTE PTR [EBP+0x57],CL//这里对参数A进行加密保存//-------分割线---(以下代码都是连续的,我人为的分开是方便大家阅读)-----------------------------0041A6EE MOV ESI,DWORD PTR [EBP+0x8] //读取opcode 指针0041A6F9 ADD ESI,0xa //opcode指针加上偏移注:Opcode指令序列可以由不同的几个部分组成的,包括subhandle 立即数虚拟寄存器号参数大小的控制参数等,长度是可变的,但具体到哪个偏移量存放那种参数却不一定,完全由handler决定0041A6FF MOVZX EAX,BYTE PTR [ESI] //读取BYTE 位的opcode ,这里我们暂且称之为参数B0041A71E SUB EAX,DWORD PTR [EBP+0x53]0041A751 XOR EAX,DWORD PTR [EBP+0xa7]0041A785 OR DWORD PTR [EBP+0x53],EAX //利用读取的Opcode对加密寄存器再加密0041A7A7 ADD DWORD PTR [EBP+0xa7],0x1b9bae7c0041A7CA SUB EAX,DWORD PTR [EBP+0x89]0041A7EC XOR DWORD PTR [EBP+0x89],0x257e43920041A7F2 MOV DL,AL0041A7F8 AND AL,0xf0//下面两个指令,分别获取参数B的高地位0041A7FC AND DL,0xf0041A7FF ADD DL,0x55//对指令B高地位分别加密0041A81B SHR AL,0x40041A824 XOR AL,0x710041A851 MOV BYTE PTR [EBP+0x4c],AL//这两个指令保存指令到VMcontext0041A873 MOV BYTE PTR [EBP+0x70],DL//注意,没有两个相同的handler这里是一样的,也就是说,具体临时变量保存在VMcontext哪里,要依据handler来定//-------分割线---(以下代码都是连续的,我人为的分开是方便大家阅读)-----------------------------0041A893 MOV EDX,DWORD PTR [EBP+0x8] //读取opcode 指针0041A895 ADD EDX,0x2 //opcode指针加上偏移0041A8AC MOV EBX,DWORD PTR [EDX]//读取参数C0041A8D6 XOR EBX,DWORD PTR [EBP+0x53]0041A8F0 XOR EBX,DWORD PTR [EBP+0x14]0041A929 OR DWORD PTR [EBP+0x53],EBX0041A93B AND DWORD PTR [EBP+0xa7],0x7f25fef30041A972 ADD EBX,DWORD PTR [EBP+0x89]0041A99A OR DWORD PTR [EBP+0x89],0x231e01c40041A9B7 XOR EBX,0x8f063b20041A9F7 ADD EBX,DWORD PTR [EBP+0x60]0041AA13 MOV DWORD PTR [EBP+0x26],EBX//-------分割线---(以下代码都是连续的,我人为的分开是方便大家阅读)-----------------------------0041AA45 MOV AL,BYTE PTR [EBP+0x4c] 读取参数B的高位0041AA47 XOR AL,0x71 //简单的解密,对应前面0041A824的代码可见0041AA49 CMP AL,0x2 //从这里开始,可以看出参数B是一个flag,他的高位控制后面的操作数是什么类型的,2为虚拟地址,1为虚拟寄存器,3为立即数(由于type1 handler中不需要立即数,所以你们不会在后面看到相应的例程)0041AA4B JNZ 0x1d0(0041AC21)0041AA72 MOV ECX,DWORD PTR [EBP+0x26]//读取参数C,如果参数B高位是2,参数C就是虚拟地址的偏移0041AAA6 SUB ECX,DWORD PTR [EBP+0x60]0041AAB2 XOR ECX,0x8f063b20041AABC AND ECX,0xffff0041AAC9 ADD ECX,EBP0041AAF5 MOV DL,BYTE PTR [EBP+0x70]//取出参数B的低位0041AB0C SUB DL,0x55//简单的解密0041AB1F MOV ECX,DWORD PTR [ECX]0041AB21 MOV EAX,ECX0041AB23 ADD EAX,0xbdc57aa0041AB4B MOV DWORD PTR [EBP+0x4],EAX0041AB4D CMP DL,0x1 //显然这是一个读取虚拟寄存器的例程,参数B的低位用来控制读取的大小0041AB50 JNZ 0x12(0041AB68)0041AB5A MOV CL,BYTE PTR [ECX]0041AB68 CMP DL,0x20041AB6B JNZ 0x9(0041AB7A)0041AB77 MOV CX,WORD PTR [ECX]0041AB7A CMP DL,0x30041AB7D JNZ 0x1b(0041AB9E)0041AB89 MOV ECX,DWORD PTR [ECX]0041ABB7 XOR ECX,0x8f063b20041ABF2 ADD ECX,DWORD PTR [EBP+0x60]0041AC19 MOV DWORD PTR [EBP+0x26],ECX//把从虚拟寄存器中读取到的数值保存0041AC30 AND DWORD PTR [EBP+0x68],0x1a49977a0041AC38 MOV BYTE PTR [EBP+0x47],0x00041AC43 MOV DL,BYTE PTR [EBP+0x4c]0041AC45 XOR DL,0x710041AC48 CMP DL,0x10041AC4B JNZ 0x50(0041ACA1)//如果参数B的高位是1的话,就是对虚拟寄存器的读取0041AC59 MOV ECX,DWORD PTR [EBP+0x26]//读取参数C0041AC63 SUB ECX,DWORD PTR [EBP+0x60]0041AC65 XOR ECX,0x8f063b20041AC6B AND ECX,0xffff0041AC71 ADD ECX,EBP0041AC73 MOV EDX,ECX0041AC75 ADD ECX,0xbdc57aa0041AC83 MOV DWORD PTR [EBP+0x4],ECX//读取的地址后面还要用到,所以先加密保存0041AC85 MOV ECX,DWORD PTR [EDX]//读取地址中的数值0041AC87 XOR ECX,0x8f063b20041AC95 ADD ECX,DWORD PTR [EBP+0x60]0041AC9F MOV DWORD PTR [EBP+0x26],ECX//保存地址中的数值0041ACA9 SUB DWORD PTR [EBP+0x8f],0x18830b950041ACB7 OR DWORD PTR [EBP+0x8f],0x2223c95f//-------分割线---(以下代码都是连续的,我人为的分开是方便大家阅读)-----------------------------0041ACC5 MOV BL,BYTE PTR [EBP+0x57]//读取参数A0041ACC7 SUB BL,0xb20041ACCA CMP BL,0x72//好了,我们可以确定参数A就是subhandle了,如果subhandle是0x72,那么就是DEC的操作0041ACCD JNZ 0x2a(0041ACFD)0041ACDB MOV EAX,DWORD PTR [EBP+0x26]0041ACE5 SUB EAX,DWORD PTR [EBP+0x60]0041ACE7 XOR EAX,0x8f063b20041ACEC DEC EAX0041ACED PUSHFD 0041ACEE ADD EAX,0x5d85656d0041ACFB MOV DWORD PTR [EBP+0x7f],EAX//保存计算后的结果0041AD17 MOV DL,BYTE PTR [EBP+0x57]0041AD1B SUB DL,0xb20041AD1E CMP DL,0x96 //如果subhandle是96,就进行NEG操作0041AD21 JNZ 0x94(0041ADBB)0041AD55 MOV EDX,DWORD PTR [EBP+0x26]0041AD78 SUB EDX,DWORD PTR [EBP+0x60]0041AD8C XOR EDX,0x8f063b20041AD92 NEG EDX0041AD94 PUSHFD 0041AD95 ADD EDX,0x5d85656d0041ADA9 MOV DWORD PTR [EBP+0x7f],EDX0041ADF5 MOV AL,BYTE PTR [EBP+0x57]0041AE04 SUB AL,0xb20041AE06 CMP AL,0x39 同上,这里是NOT0041AE08 JNZ 0x9a(0041AEA8)0041AE32 MOV EBX,DWORD PTR [EBP+0x26]0041AE5D SUB EBX,DWORD PTR [EBP+0x60]0041AE65 XOR EBX,0x8f063b20041AE6B NOT EBX0041AE6D CMP ECX,EDX0041AE6F PUSHFD 0041AE72 ADD EBX,0x5d85656d0041AEA6 MOV DWORD PTR [EBP+0x7f],EBX0041AEBD SUB DWORD PTR [EBP+0x53],0x47572fe70041AEBF MOV CL,BYTE PTR [EBP+0x57]0041AEC3 SUB CL,0xb20041AEC6 CMP CL,0x41 //下面的我就不一一说明了,大家自己看看,看看能不能找到是什么操作0041AEC9 JNZ 0x2c(0041AEFB)0041AED7 MOV ESI,DWORD PTR [EBP+0x26]0041AEE1 SUB ESI,DWORD PTR [EBP+0x60]0041AEE3 XOR ESI,0x8f063b20041AEE9 INC ESI0041AEEA PUSHFD 0041AEEB ADD ESI,0x5d85656d0041AEF9 MOV DWORD PTR [EBP+0x7f],ESI0041AF01 AND DWORD PTR [EBP+0x14],0x47572fe70041AF2B MOV BL,BYTE PTR [EBP+0x57]0041AF32 SUB BL,0xb20041AF35 CMP BL,0xc10041AF38 JE 0x165(0041B0A3)0041AF3E CMP BL,0x60041AF41 JE 0x15c(0041B0A3)0041AF8A MOV DL,BYTE PTR [EBP+0x70]//再次读取参数B的低位0041AF9D MOV EAX,DWORD PTR [EBP+0x4]0041AFB1 SUB EAX,0xbdc57aa0041AFCA SUB DL,0x550041AFF4 MOV EBX,DWORD PTR [EBP+0x7f]0041B000 SUB EBX,0x5d85656d0041B006 CMP DL,0x1//进行大小的判断,下面就是要保存计算结果了0041B009 JNZ 0xf(0041B01E)0041B014 MOV BYTE PTR [EAX],BL0041B01E CMP DL,0x20041B021 JNZ 0x7(0041B02E)0041B029 MOV WORD PTR [EAX],BX0041B02E CMP DL,0x30041B031 JNZ 0x3d(0041B074)0041B043 MOV DWORD PTR [EAX],EBX0041B0B6 POP EDX//-------分割线---(以下代码都是连续的,我人为的分开是方便大家阅读)-----------------------------//以下这段不经常用到,就是如果opcode中设置另外个flag的话,是可以读取计算中的EFLAGS寄存器的结果的0041B0C4 MOV ECX,DWORD PTR [EBP+0x8]0041B0D9 XOR DWORD PTR [EBP+0x53],0x1e4ffb660041B10A SUB DWORD PTR [EBP+0xa7],0x1d2ace370041B112 ADD ECX,0x60041B129 MOVZX ECX,BYTE PTR [ECX]0041B12C CMP ECX,0x00041B132 JE 0x85(0041B1BD)0041B180 MOV EDI,DWORD PTR [EBP+0x8]0041B182 ADD EDI,0x00041B196 MOV CX,WORD PTR [EDI]0041B19E ADD ECX,EBP0041B1AD MOV DWORD PTR [ECX],EDX//-------分割线---(以下代码都是连续的,我人为的分开是方便大家阅读)-----------------------------//最后这段,每个handle都会有,就是重新设置opcode的偏移,读取下一个handler号并跳转,大家可以自己阅读一下0041B1DF MOV EDX,DWORD PTR [EBP+0x8]0041B1E8 MOV ESI,DWORD PTR [EBP+0x4f]//这里是handler指针表0041B1EC ADD EDX,0x70041B1FA MOVZX EDX,WORD PTR [EDX]0041B20E ADD EDX,DWORD PTR [EBP+0x53]0041B242 XOR EDX,0xf833c890041B274 XOR DWORD PTR [EBP+0x53],EDX0041B278 AND EDX,0xffff0041B280 SHL EDX,0x20041B28D ADD ESI,EDX0041B298 MOV EDI,DWORD PTR [ESI]0041B2A4 ADD DWORD PTR [EBP+0x8],0xb0041B2AA JMP EDI
{001B} [00000039-7D54B913-0000001A-00000000-00000000] NOT EBP
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课