此类指令都为6个字节
大致试验结果如下:
第一个字节跟操作类型相关,第二个字节跟寄存器相关,后面四个字节为地址
第二个字节高四位必须为8,9,A,B四个中的一个,低四位必为5和D中的一个,产生8种排列组合,分别代表8个寄存器
第一个能够使用到[EBP+XXXX]的操作数如下:
0X ADD/OR
1X ADC/SBB
2X SUB/ADD
3X CMP/XOR
8X ADD/MOV/LEA/POP/XCHG/TEST
CX ROL/LDS/MOV
DX ROL/FADD
FX INC/CALL/TEST
修改方法:
假定OFFSET小于两个字节,则搜索0000串,往前推三个字节和四个字节,使用上述条件判断,如果满足上述条件,则将第二个字节减去0x80h,并将地址加上偏移
修复代码如下:
char *pDoubleNull;
char *pEnd=(char*)lpBuffer+nBufferSize;
int nSearchSize=nBufferSize;
char* lpSearchBuffer=lpBuffer;
do
{
pDoubleNull=(char*)memchr(lpSearchBuffer,'\0',nSearchSize);
if(NULL==pDoubleNull)
break;
nSearchSize=(int)(pEnd-pDoubleNull);
lpSearchBuffer=pDoubleNull+1;
if('\0'!=*(pDoubleNull+1))
continue;
if(0=*(WORD*)(pDoubleNull+2))//Exclude lea ecx, ds:0[ecx*8] etc.
{
lpSearchBuffer+=3;
continue;
}
lpSearchBuffer++;
unsigned char bFirHigh,bSecHigh,bSecLow;
if(NULL==*(pDoubleNull-4)||NULL==*(pDoubleNull-3)||0x850F=*(WORD*)(pDoubleNull-4))//Exclude jnz
continue;
bFirHigh=(*(pDoubleNull-4))&0xF0;
bSecHigh=(unsigned char)((*(pDoubleNull-3))&0xF0)>>4;
bSecLow=(*(pDoubleNull-3))&0xF;
if((0x5==bSecLow||0xD==bSecLow)&&(bSecHigh>=0x8&&bSecHigh<=0xB))
if(0==bFirHigh||0x10==bFirHigh||0x20==bFirHigh||0x30==bFirHigh||0x80==bFirHigh||0xC0==bFirHigh||0xD0==bFirHigh||0xF0==bFirHigh)
{
*(pDoubleNull-3)-=0x80;
*(DWORD*)(pDoubleNull-2)+=nOffsetAddr;
}
}while(lpSearchBuffer<=(pEnd-6));
注:1.可能存在个别偏移为单字节的未能修复,需再使用手动修复
2. 此方法亦可用于把正常CODE修改为重定向