其他
vmp 相关的问题
本文为看雪论坛精华文章
看雪论坛作者ID:L0x1c
1
搭建环境
2
模拟环境
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#pragma warning(disable : 4996)
char buf[1204];
void main()
{
while (1)
{
scanf("%s", buf);
if (!strcmp(buf, "123"))
printf("ok\n");
else
printf("fail\n");c
}
}
case 0x473594:
{
DWORD val = 0x00343332;
uc_mem_write(uc, 0x403370, &val, 4);
regs.regs.r_eip = 0x47295d;
uc_reg_write(uc, UC_X86_REG_EIP, ®s.regs.r_eip);
regs.regs.r_esp += 8;
uc_reg_write(uc, UC_X86_REG_ESP, ®s.regs.r_esp);
}
case 0x472ecc:
{
regs.regs.r_eax = 1;
err = uc_reg_write(uc, X86_REG_EAX, ®s.regs.r_eax);
regs.regs.r_eip = 0x4854c1;
err = uc_reg_write(uc, X86_REG_EIP, ®s.regs.r_eip);
regs.regs.r_esp += 8;
err = uc_reg_write(uc, X86_REG_ESP, ®s.regs.r_esp);
}
3
代码块
!strcmp(insn->mnemonic,"ret")||(!strcmp(insn->mnemonic,"jmp") && insn->detail->x86.operands[0].type != X86_OP_IMM)||!strcmp(insn->mnemonic,"call")||(insn ->mnemonic[0] == 'j' && insn->detaicl->regs_read_count == 1 && insn->detail->regs_read[0] == X86_REG_EFLAGS)
push reg
ret
4
局部混淆
Emulate i386 code
00485B76 push 0x4cc49084
00485B7B call 0x441d33
00441D33 pushfd
00441D34 stc
00441D35 clc
00441D36 push edi
00441D37 rcl edi, 0x6b
00441D3A xchg edi, edi
00441D3C push edx
00441D3D btr edi, edi
00441D40 push ecx
00441D41 btr di, ax
00441D45 rol edi, 0xc
00441D48 bswap cx
00441D4B push eax
00441D4C push esi
00441D4D push ebx
00441D4E clc
00441D4F push ebp
00441D50 bswap si
00441D53 bts eax, ebx
00441D56 mov ecx, 0
00441D5B cbw
00441D5D push ecx
00441D5E mov bl, 0x99
00441D60 clc
00441D61 mov esi, dword ptr [esp + 0x28]
00441D65 btr edi, edx
00441D68 not bp
00441D6B bts edi, eax
00441D6E ror esi, 1
00441D70 movzx eax, bp
00441D73 bsf eax, esi
00441D76 lea esi, [esi - 0x1394580a]
00441D7C bswap esi
00441D7E sal al, 0xe6
00441D81 sbb bx, bp
00441D84 xor esi, 0x5bf674ed
00441D8A movsx ebp, cx
00441D8D btc ebx, ebx
00441D90 not esi
00441D92 adc bp, 0x66ec
00441D97 stc
00441D98 bswap esi
00441D9A and ebp, 0xa934b31
00441DA0 stc
00441DA1 lea esi, [esi + ecx]
00441DA4 lahf
00441DA5 mov ebp, esp
00441DA7 lea esp, [esp - 0xc0]
00441DAE rcl ebx, cl
00441DB0 mov edi, ecx
00441DB2 mov ebx, esi
00441DB4 xadd di, cx
00441DB8 mov eax, 0
00441DBD xor edi, eax
00441DBF sub ebx, eax
00441DC1 or edi, 0x1a7d74b8
00441DC7 rcl di, 0xe5
00441DCB lea edi, [0x441dcb]
00441DD1 rcr ecx, cl
00441DD3 mov ecx, dword ptr [esi]
00441DD5 stc
00441DD6 add esi, 4
00441DDC xor ecx, ebx
00441DDE jmp 0x42fdc3
0042FDC3 bswap ecx
0042FDC5 jmp 0x47eef0
0047EEF0 dec ecx
0047EEF1 stc
0047EEF2 neg ecx
0047EEF4 jmp 0x40bc45
0040BC45 add ecx, 0x2941083
0040BC4B clc
0040BC4C test dl, 0x4c
0040BC4F xor ebx, ecx
0040BC51 add edi, ecx
0040BC53 push edi
0040BC54 ret
00441D33 pushfd
00441D36 push edi
00441D3C push edx
00441D40 push ecx
00441D4B push eax
00441D4C push esi
00441D4D push ebx
00441D4F push ebp
00441D56 mov ecx, 0
00441D5D push ecx
00441D5E mov bl, 0x99
00441D61 mov esi, dword ptr [esp + 0x28]
00441D6E ror esi, 1
00441D76 lea esi, [esi - 0x1394580a]
00441D7C bswap esi
00441D84 xor esi, 0x5bf674ed
00441D90 not esi
00441D98 bswap esi
00441DA1 lea esi, [esi + ecx]
00441DA5 mov ebp, esp
00441DA7 lea esp, [esp - 0xc0]
00441DB2 mov ebx, esi
00441DB8 mov eax, 0
00441DBF sub ebx, eax
00441DCB lea edi, [0x441dcb]
00441DD3 mov ecx, dword ptr [esi]
00441DD6 add esi, 4
00441DDC xor ecx, ebx
0042FDC3 bswap ecx
0047EEF0 dec ecx
0047EEF2 neg ecx
0040BC45 add ecx, 0x2941083
0040BC4C test dl, 0x4c
0040BC4F xor ebx, ecx
0040BC51 add edi, ecx
0040BC53 push edi
0040BC54 ret
9c 57 52 51 50 56 53 55 b9 00 00 00 00 51 b3 99 8b 74 24 28 d1 ce 8d b6 f6 a7 6b ec 0f ce 81 f6 ed 74 f6 5b f7 d6 0f ce 8d 34 0e 8b ec 8d a4 24 40 ff ff ff 8b de b8 00 00 00 00 2b d8 3e 8d 3d cb 1d 44 00 8b 0e 83 c6 04 33 cb 0f c9 49 f7 d9 81 c1 83 10 94 02 f6 c2 4c 33 d9 03 f9 57 c3
指令的功能在于写 对于同一个位置的连续两次写,第一次写是无效的
5
函数调用界面
第二个函数调用界面,可以理解成我们自己写的函数比如就是图上的mystrcmp函数他进行了开启了优化,相当于将自定义函数进行了内联,加上vmp就是相当于第二张图的形式。
第三张图函数调用界面一写debug版的编译会出现这个状况,我们会有出虚拟机,再进虚拟机,再出再进的一个标识在。
第四张图就是如果不开优化,我们的正常的加vmp的一个形式,将我们的main和我们自定义的函数都加上vmp。
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#pragma warning(disable : 4996)
char buf[1204];
bool mystrcmp(char* p1, const char* p2)
{
while (*p1 & *p2)
{
if (*p1 != *p2)
return false;
p1++;
p2++;
}
if (*p1 || *p2)
return false;
return true;
}
void main()
{
while (1)
{
scanf("%s", buf);
if (mystrcmp(buf, "123"))
printf("ok\n");
else
printf("fail\n");
}
}
00449668 call 0x46af7e ;进入虚拟机
0043FC17 call 0x46af7e ;scanf后进入虚拟机
00467D9E call 0x47608d ;mystrcmp后进入虚拟机
6
黑盒测试
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
typedef void (*CALL)();
void p1()
{
printf("in p1\n");
}
void p2()
{
printf("in p2\n");
}
#define IS_ZERO(x) 1-((x)|(-x))>>31
void nojcc(int a, int b, CALL f1, CALL f2)
{
__asm
{
mov eax,a //输入的参数1 到eax
sub eax,b //看是否是等于0
pushfd //减法会打扰eflag的值
pop eax //把eflag的值传给eax
and eax,0x40 //看第6位是否等于1 即ZF是否等于1
shr eax,6 //左移6位看是否变成了1
mov ecx,1 //ecx置1
sub ecx,eax //将ecx和eax相减,如果eax等于0的情况就是不相等,如果等于1的情况就是相等
neg eax //eax如果是1 取反等于0xffffffff 如果不是就是0
neg ecx //同上
and eax,f1 //eax和f1进行相与,如果他相等了就是1那么neg就是0xffffffff 结果就是f1
and ecx,f2 //同上
add eax,ecx //因为有一个是0 所以一定是有值的
call eax //call最后的结果即可
}
}
void main()
{
nojcc(1, 1, p1, p2);
system("pause");
}
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
typedef void (*CALL)();
void p1()
{
printf("in p1\n");
}
void p2()
{
printf("in p2\n");
}
#define IS_ZERO(x) 1-((x)|(-x))>>31
void nojcc(int a, int b, CALL f1, CALL f2)
{
__asm
{
mov eax,a //eax = a
sub eax,b //eax - b 看是否等于0
mov ecx,eax //ecx = eax
neg eax //eax 取反
or eax,ecx //如果进行抑或不是0的话他们就会等于-1
shr eax,31 //eax留下符号位,因为-1的符号位是1,所以只有a=b的时候shr eax 31 = 0
mov ecx,1 //ecx = 1
sub ecx,eax //ecx = ecx - eax
mov eax,ecx //eax = ecx
mov ecx,1 //ecx = 1
sub ecx,eax //ecx = ecx - eax
neg eax //同上了
neg ecx
and eax,f1
and ecx,f2
add eax,ecx
call eax
}
}
void main()
{
nojcc(1, 1, p1, p2);
system("pause");
}
推理: a-b
NOT(NOT(a)+b) = a-b
NOT(a) = -a -1 (视为有符号)
NOT(-a-1+b) = a + 1 - b - 1 = a - b
//无符号的状态
NOT(a) = 2^32 - a - 1
2^32 - a - 1 + b > = 2 ^ 32 如果大于等于2^32的时候就溢出了 开始置C位
b >= a + 1
b > a
a - b 置C
//有符号的状态
NOT(a) = -a - 1
(a>=0 b<0 a-b >= 2^31) / (a<=0 b>0 a-b < - 2^31)
(-a<=0 b<0 -a-1+b < -2^31) / (-a-1>=-1 b>0 -a-1+b >= 2^31)
(-a - 1<0 b<0 -a-1+b < -2^31) / (-a-1>0 b>0 -a-1+b >= 2^31)
等价于NOT(a) + b 置O
00482F8B pushfd
00436418 pushfd
0046639B pushfd
0041F1F4 pushfd
00420A7E pushfd
00429CF9 pushfd
0048A175 pushfd
0046EBD4 pushfd
00421087 pushfd
0042B5BE pushfd
00464DE9 pushfd
0047D936 pushfd
00421729 pushfd
0048CBC9 pushfd
004335A8 pushfd
0048C880 pushfd
00484710 pushfd
//判断是什么寄存器
DWORD get_reg(x86_reg reg) {
switch (reg) {
case X86_REG_EAX:
return regs.regs.r_eax;
case X86_REG_AX:
return regs.regs.r_eax & 0xffff;
case X86_REG_AH:
return (regs.regs.r_eax >> 8) & 0xff;
case X86_REG_AL:
return regs.regs.r_eax & 0xff;
case X86_REG_ECX:
return regs.regs.r_ecx;
case X86_REG_CX:
return regs.regs.r_ecx & 0xffff;
case X86_REG_CH:
return (regs.regs.r_ecx >> 8) & 0xff;
case X86_REG_CL:
return regs.regs.r_ecx & 0xff;
case X86_REG_EDX:
return regs.regs.r_edx;
case X86_REG_DX:
return regs.regs.r_edx & 0xffff;
case X86_REG_DH:
return (regs.regs.r_edx >> 8) & 0xff;
case X86_REG_DL:
return regs.regs.r_edx & 0xff;
case X86_REG_EBX:
return regs.regs.r_ebx;
case X86_REG_BX:
return regs.regs.r_ebx & 0xffff;
case X86_REG_BH:
return (regs.regs.r_ebx >> 8) & 0xff;
case X86_REG_BL:
return regs.regs.r_ebx & 0xff;
case X86_REG_ESP:
return regs.regs.r_esp;
case X86_REG_SP:
return regs.regs.r_esp & 0xffff;
case X86_REG_EBP:
return regs.regs.r_ebp;
case X86_REG_BP:
return regs.regs.r_ebp & 0xffff;
case X86_REG_ESI:
return regs.regs.r_esi;
case X86_REG_SI:
return regs.regs.r_esi & 0xffff;
case X86_REG_EDI:
return regs.regs.r_edi;
case X86_REG_DI:
return regs.regs.r_edi & 0xffff;
case X86_REG_EIP:
return regs.regs.r_eip;
case X86_REG_EFLAGS:
return regs.regs.r_efl;
default:
__asm int 3
}
}
DWORD read_op(cs_x86_op op)
{
switch (op.type)
{
case X86_OP_IMM: //立即数
return op.imm;
case X86_OP_REG: //寄存器
return get_reg(op.reg);
case X86_OP_MEM: //内存地址
{
DWORD addr = get_mem_addr(op.mem);
DWORD val = 0;
uc_mem_read(uc, addr, &val, op.size);
return val;
}
}
}
!strcmp(insn->mnemonic,"pushfd")||(!strcmp(insn->mnemonic,"and") && (read_op(insn->detail->x86.operands[0])) == 0x40 || (read_op(insn->detail->x86.operands[1])) == 0x40)||(!strcmp(insn->mnemonic,"shr") && read_op(insn->detail->x86.operands[1]) == 0x6)
00429CF9 pushfd
0046EBCF and ecx, eax
00421082 shr eax, cl
0046B6F3 pushfd
00464E7F pushfd
00439BD1 pushfd
0043EB08 pushfd
0041EFCF pushfd
004818A8 pushfd
0041F922 cmp esp, edx
0041F927 and edx, ecx
00476992 pushfd
00421D22 shr eax, cl
00421D2D pushfd
0043F7E5 pushfd
00426A2B mov dl, al
00433BAB pushfd
0048C281 pushfd
00469322 pushfd
0044F6AF pushfd
00461644 pushfd
00406D91 pushfd
00432DDE pushfd
00484E50 pushfd
0043E3D4 pushfd
0047D76A pushfd
004292FE pushfd
00424EF5 pushfd
004847BE pushfd
00489C89 pushfd
00484F54 rol al, cl
004422F1 pushfd
00410E26 pushfd
0046308B mov dx, ax
0041E2FA pushfd
0041C103 pushfd
00451729 and edx, ecx
004725D1 mov dword ptr [esi + 4], edx
004725D4 pushfd
00483E8C mov eax, dword ptr [esi]
00483E8E add cl, al
00483E9B shr eax, cl
00483EA9 pushfd
0046D448 pushfd
0041074E pushfd
00470720 pushfd
0043A841 pushfd
0043A284 pushfd
004313A6 rcr cx, cl
00451B58 pushfd
0041D33F pushfd
0040AFE2 pushfd
0040DC15 pushfd
004448CD pushfd
0042FC1E pushfd
0041DB6F pushfd
004730D6 pushfd
00448E3F pushfd
0048A934 pushfd
0044F92B and eax, ecx
0044F939 pushfd
00454033 shr edx, cl
004548C6 pushfd
0047305F pushfd
00476B19 pushfd
0044F99F pushfd
004473A7 pushfd
00483B58 pushfd
004092C0 pushfd
00458B9F pushfd
00428600 pushfd
004811BF movzx ecx, byte ptr [ebp]
0041F927 and edx, ecx
00421D22 shr eax, cl
00451729 and edx, ecx
00483E9B shr eax, cl
0044F92B and eax, ecx
00454033 shr edx, cl
004695F5 and ecx, eax
0043CB41 shr eax, cl
00473A47 and ecx, edx
0046B07D shr eax, cl
0040A211 and ecx, eax
00431FB2 shr eax, cl
7
侧信道攻击
8
污点分析
在一个指令中,如果有至少一个读位置是污染的,就将所有的写位置污染。
在一条指令中,如果所有的读位置都是非污染的,那么就将所有的写位置去污染。
if (!strcmp(insn->mnemonic, "push"))
{//push
cs_x86_op op = x86.operands[0];
do_taint_sp_push(op);
return g_taint_handled;
}
/* ------------------------------------------------------------------- */
inline static void do_taint_sp_push(cs_x86_op& op)
{
DWORD esp_after = regs.u[reg_transfer_table[X86_REG_ESP]] - 4;
switch (op.type)
{
case X86_OP_MEM:
{
DWORD addr = get_mem_addr(op.mem);
if (is_addr_tainted(addr) || is_addr_tainted(addr + 1) || is_addr_tainted(addr + 2) || is_addr_tainted(addr + 3)) {
for (int i = 0; i < 4; i++)
taint_addr(esp_after + i);
}
else {
for (int i = 0; i < 4; i++)
untaint_addr(esp_after + i);
}
}
break;
case X86_OP_REG:
{
x86_reg reg = op.reg;
if (is_reg_tainted(reg)) {
for (int i = 0; i < 4; i++)
taint_addr(esp_after + i);
}
else {
for (int i = 0; i < 4; i++)
untaint_addr(esp_after + i);
}
}
break;
case X86_OP_IMM:
for (int i = 0; i < 4; i++)
untaint_addr(esp_after + i);
break;
default:
__asm int 3
}
}
看雪ID:L0x1c
https://bbs.pediy.com/user-home-873515.htm
# 往期推荐
2.通过CmRegisterCallback学习注册表监控与反注册表监控
3.Android APP漏洞之战——权限安全和安全配置漏洞详解
5.通过对PsSetCreateProcessNotifyRoutineEx的逆向分析得出的结果来实现反进程监控
球分享
球点赞
球在看
点击“阅读原文”,了解更多!