detours 通过修改输入表注入DLL -- UpdateImports 函数的分析

Detours学习之十三:Detours API用于将dll和有效负载插入新进程的api 用于将dll和有效负载插入新进程的api DetourCreateProcessWithDllEx DetourCreateProcessWithDlls DetourCopyPayloadToProcess DetourCopyPayloadToProcessEx DetourFinishHelperProcess DetourIsHelperProcess DetourRestoreAfterWith 一、DetourCreateProcessWithDllEx 创建一个新进程并将DLL 阅读详情
 

前段时间有一个需求,就是在进程启动的第一时间实现dll的注入,当时一想以为很简单嘛,比如拦截CreateProcessInternalW等不就行了吗?后来发现如果你在CreateProcessInternalW前处理进程还没有启动,而之后处理的话,进程的主线程已经开始工作了,再后来通过修改创建标志把创建的进程的主线程挂起,等进程创建后我来注入,此时才发现创建远线程搞不定, 此时进程只有NTDLL,其他模块还没有加载呢.再最后终于发现了detours 2.1为我们提供了一个函数DetourCreateProcessWithDllW,它可以实现在进程创建初期就将dll加载进去,下面我就来分析一下detours怎么做到在进程初期就将dll加载进程的.

先来看DetourCreateProcessWithDllW函数,可以分为四个步骤:

BOOL 
WINAPI 
DetourCreateProcessWithDllW(LPCWSTR lpApplicationName,
                            __in_z LPWSTR lpCommandLine,
                            LPSECURITY_ATTRIBUTES lpProcessAttributes,
                            LPSECURITY_ATTRIBUTES lpThreadAttributes,
                            BOOL bInheritHandles,
                            DWORD dwCreationFlags,
                            LPVOID lpEnvironment,
                            LPCWSTR lpCurrentDirectory,
                            LPSTARTUPINFOW lpStartupInfo,
                            LPPROCESS_INFORMATION lpProcessInformation,
                            LPCSTR lpDetouredDllFullName,
                            LPCSTR lpDllName,
                            PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
{
    
// 第一步:修改创建标志位
    DWORD dwMyCreationFlags = (dwCreationFlags | CREATE_SUSPENDED);
    PROCESS_INFORMATION pi;

    
if (pfCreateProcessW == NULL) {
        pfCreateProcessW 
= CreateProcessW;
    }


    
// 第二步:调用原始CreateProcessW
    if (!pfCreateProcessW(lpApplicationName,
                          lpCommandLine,
                          lpProcessAttributes,
                          lpThreadAttributes,
                          bInheritHandles,
                          dwMyCreationFlags,
                          lpEnvironment,
                          lpCurrentDirectory,
                          lpStartupInfo,
                          
&pi)) {
        
return FALSE;
    }


    LPCSTR rlpDlls[
2];
    DWORD nDlls 
= 0;
    
if (lpDetouredDllFullName != NULL) {
        rlpDlls[nDlls
++] = lpDetouredDllFullName;
    }

    
if (lpDllName != NULL) {
        rlpDlls[nDlls
++] = lpDllName;
    }


    
// 第三步: 修改目标进程的输入表
    if (!UpdateImports(pi.hProcess, rlpDlls, nDlls)) {
        
return FALSE;
    }


    
if (lpProcessInformation) {
        CopyMemory(lpProcessInformation, 
&pi, sizeof(pi));
    }


    
// 第四步: 让目标进程的主线程继续运行
    if (!(dwCreationFlags & CREATE_SUSPENDED)) {
        ResumeThread(pi.hThread);
    }

    
return TRUE;
}

呵呵,看出来了,原来detours使用的是修改输入表来实现dll的注入的,在来看其中最关键的函数UpdateImports,

BOOL WINAPI UpdateImports(HANDLE hProcess, LPCSTR *plpDlls, DWORD nDlls)
{
    BOOL fSucceeded 
= FALSE;
    BYTE 
* pbNew = NULL;
    DETOUR_EXE_RESTORE der;
    DWORD i;

    ZeroMemory(
&der, sizeof(der));
    der.cb 
= sizeof(der);

    
// 从 0x10000 开始寻找MEM_IMGAE标志的内存,然后验证其是否是exe
    
// 如果是那么返回其首地址
    PBYTE pbModule = (PBYTE)FindExe(hProcess);

    IMAGE_DOS_HEADER idh;
    ZeroMemory(
&idh, sizeof(idh));

    
// 读取 IMAGE_DOS_HEADER
    if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
        DETOUR_TRACE((
"ReadProcessMemory(idh) failed: %d ", GetLastError()));

      finish:
        
if (pbNew != NULL) {
            delete[] pbNew;
            pbNew 
= NULL;
        }

        
return fSucceeded;
    }

    CopyMemory(
&der.idh, &idh, sizeof(idh));
    der.pidh 
= (PIMAGE_DOS_HEADER)pbModule;

    
// 验证是否是 MZ
    if (idh.e_magic != IMAGE_DOS_SIGNATURE) {
        
goto finish;
    }


    IMAGE_NT_HEADERS inh;
    ZeroMemory(
&inh, sizeof(inh));

    
// 读取 IMAGE_NT_HEADERS
    if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), NULL)) {
        DETOUR_TRACE((
"ReadProcessMemory(inh) failed: %d ", GetLastError()));
        
goto finish;
    }

    CopyMemory(
&der.inh, &inh, sizeof(inh));
    der.pinh 
= (PIMAGE_NT_HEADERS)(pbModule + idh.e_lfanew);

    
// 验证是否是PE, 和验证MZ一样,没有多大必要,其实在FindExe里面都验证过了
    if (inh.Signature != IMAGE_NT_SIGNATURE) {
        
goto finish;
    }


    
// 如果没有导入表,直接返回
    if (inh.IMPORT_DIRECTORY.VirtualAddress == 0) {
        DETOUR_TRACE((
"No IMAGE_DIRECTORY_ENTRY_IMPORT "));
        
goto finish;
    }


    
// Zero out the bound table so loader doesn't use it instead of our new table.
    
// 不懂为什么要这样
    inh.BOUND_DIRECTORY.VirtualAddress = 0;
    inh.BOUND_DIRECTORY.Size 
= 0;

    
// Find the size of the mapped file.
    
    DWORD dwFileSize 
= 0;

    
// FIELD_OFFSET 这个宏很精妙
    
// 得到 section 的偏移
    DWORD dwSec = idh.e_lfanew +
        FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) 
+
        inh.FileHeader.SizeOfOptionalHeader;

    
// 循环读取 节,主要作用就是计算文件的大小,然而文件大小本身又用不到,所以这个东西就是鸡肋
    for (i = 0; i < inh.FileHeader.NumberOfSections; i++) {
        IMAGE_SECTION_HEADER ish;
        ZeroMemory(
&ish, sizeof(ish));

        
if (!ReadProcessMemory(hProcess, pbModule + dwSec + sizeof(ish) * i, &ish,
                               
sizeof(ish), NULL)) {
            DETOUR_TRACE((
"ReadProcessMemory(inh) failed: %d ", GetLastError()));
            
goto finish;
        }


        DETOUR_TRACE((
"ish[%d] : va=%p sr=%d ", i, ish.VirtualAddress, ish.SizeOfRawData));

        
// If the file didn't have an IAT_DIRECTORY, we create one...
        
// 不能理解其深意
        if (inh.IAT_DIRECTORY.VirtualAddress == 0 &&
            inh.IMPORT_DIRECTORY.VirtualAddress 
>= ish.VirtualAddress &&
            inh.IMPORT_DIRECTORY.VirtualAddress 
< ish.VirtualAddress + ish.SizeOfRawData) {

            inh.IAT_DIRECTORY.VirtualAddress 
= ish.VirtualAddress;
            inh.IAT_DIRECTORY.Size 
= ish.SizeOfRawData;
        }


        
// Find the end of the file...
        if (dwFileSize < ish.PointerToRawData + ish.SizeOfRawData) {
            dwFileSize 
= ish.PointerToRawData + ish.SizeOfRawData;
        }

    }

    DETOUR_TRACE((
"dwFileSize = %08x ", dwFileSize));

    
// Find the current checksum.
    WORD wBefore = ComputeChkSum(hProcess, pbModule, &inh);
    DETOUR_TRACE((
"ChkSum: %04x + %08x => %08x ", wBefore, dwFileSize, wBefore + dwFileSize));

    DETOUR_TRACE((
"     Imports: %8p..%8p ",
                  (DWORD_PTR)pbModule 
+ inh.IMPORT_DIRECTORY.VirtualAddress,
                  (DWORD_PTR)pbModule 
+ inh.IMPORT_DIRECTORY.VirtualAddress +
                  inh.IMPORT_DIRECTORY.Size));

    DWORD obRem 
= sizeof(IMAGE_IMPORT_DESCRIPTOR) * nDlls;
    
// 园整
    DWORD obTab = PadToDwordPtr(obRem + inh.IMPORT_DIRECTORY.Size);
    
// 用来存储 OriginalFirstThunk 和 FirstThunk指向的数组
    
// 每个数组包括一个有用的和一个结尾的,加起来就是4个DWORD_PTR
    
// 当然还要乘以 nDlls
    DWORD obDll = obTab + sizeof(DWORD_PTR) * 4 * nDlls;
    DWORD obStr 
= obDll;
    DWORD cbNew 
= obStr;
    DWORD n;
    
for (n = 0; n < nDlls; n++) {
        cbNew 
+= PadToDword((DWORD)strlen(plpDlls[n]) + 1);
    }


    
// 现在本地分配一个缓冲区,填充好数据后再写到远程进程去
    pbNew = new BYTE [cbNew];
    
if (pbNew == NULL) {
        DETOUR_TRACE((
"new BYTE [cbNew] failed. "));
        
goto finish;
    }

    ZeroMemory(pbNew, cbNew);

    PBYTE pbBase 
= pbModule;
    PBYTE pbNext 
= pbBase
        
+ inh.OptionalHeader.BaseOfCode
        
+ inh.OptionalHeader.SizeOfCode
        
+ inh.OptionalHeader.SizeOfInitializedData
        
+ inh.OptionalHeader.SizeOfUninitializedData;
    
if (pbBase < pbNext) {
        pbBase 
= pbNext;
    }

    DETOUR_TRACE((
"pbBase = %p ", pbBase));

    
// 在远进程中分配一个和本地一样的大的 IMPORT 表,比便以后写进去
    PBYTE pbNewIid = FindAndAllocateNearBase(hProcess, pbBase, cbNew);
    
if (pbNewIid == NULL) {
        DETOUR_TRACE((
"FindAndAllocateNearBase failed. "));
        
goto finish;
    }


    
    DWORD dwProtect 
= 0;
    der.impDirProt 
= 0;
    
// 修改远程进程的输入表的属性,修改为PAGE_EXECUTE_READWRITE,其实没有必要,不要执行就可以了
    
// 反正以后要改回来的
    if (!VirtualProtectEx(hProcess,
                          pbModule 
+ inh.IMPORT_DIRECTORY.VirtualAddress,
                          inh.IMPORT_DIRECTORY.Size, PAGE_EXECUTE_READWRITE, 
&dwProtect)) {
        DETOUR_TRACE((
"VirtualProtextEx(import) write failed: %d ", GetLastError()));
        
goto finish;
    }

    DETOUR_TRACE((
"IMPORT_DIRECTORY perms=%x ", dwProtect));
    der.impDirProt 
= dwProtect;

    
// pbNewIid 是我们在远程线程分配的新的输入表的首地址,和pbModule想减后就得到它的RVA了
    DWORD obBase = (DWORD)(pbNewIid - pbModule);

    
// 将旧的输入表读入到本地,注意有一个偏移obRem
    if (!ReadProcessMemory(hProcess,
                           pbModule 
+ inh.IMPORT_DIRECTORY.VirtualAddress,
                           pbNew 
+ obRem,
                           inh.IMPORT_DIRECTORY.Size, NULL)) 
{
        DETOUR_TRACE((
"ReadProcessMemory(imports) failed: %d ", GetLastError()));
        
goto finish;
    }


    PIMAGE_IMPORT_DESCRIPTOR piid 
= (PIMAGE_IMPORT_DESCRIPTOR)pbNew;
    DWORD_PTR 
*pt;

    
// 这里是最关键的地方了,修改出一个新的输入表,当下面这个循环执行完成之后就在本地形成了
    
// 一个新的输入表了,下面这个图就是循环完成之后的内存布局图,
    
// 我们以添加两个dll为列
/*
________
________ IID 1   如:A.dll
________ IID 2   如:B.dll
________ IID 3   这后面的IID就是exe自身的, 看看上面一个ReadProcessMemory就了解了
________ IID 4   
________ IID N
________ NULL  IID结尾符号
________ IID 1 的 OriginalFirstThunk指向的数组 ,占用两个DWORD,第一个是序号输入值,第二个为NULL
________ IID 1 的FirstThunk指向的数组 ,占用两个DWORD,第一个是讯号输入值,第二个为NULL
________ IID 2 的OriginalFirstThunk指向的数组 ,占用两个DWORD,第一个是序号输入值,第二个为NULL
________ IID 2 的FirstThunk指向的数组 ,占用两个DWORD,第一个是讯号输入值,第二个为NULL
________ A.dll 的名称字符串 "全路径+A.dll",IID 1的Name字段指向这里
________ B.dll 的名称字符串 "全路径+A.dll",IID 2的Name字段指向这里
*/

    
for (n = 0; n < nDlls; n++) {
        
// 填充路径字符串
        HRESULT hrRet = StringCchCopyA((char*)pbNew + obStr, cbNew - obStr, plpDlls[n]);
        
if (FAILED(hrRet))
        
{
            DETOUR_TRACE((
"StringCchCopyA failed: %d ", GetLastError()));
            
goto finish;
        }


        
// 得到OriginalFirstThunk指向的数组的偏移
        DWORD nOffset = obTab + (sizeof(DWORD_PTR) * (4 * n));
        
// 根据偏移+首地址,就得到RVA,然后填充到IID中
        piid[n].OriginalFirstThunk = obBase + nOffset;
        
// 得到本地实际的地址
        pt = ((DWORD_PTR*)(pbNew + nOffset));
        
// 使用序号来导入, 因此注入的DLL必须至少有一个导出函数
        pt[0] = IMAGE_ORDINAL_FLAG + 1;
        pt[
1] = 0; // 数组末尾填充NULL

        
// 偏移两个DWORD,配置FirstThunk,和OriginalFirstThunk类似
        nOffset = obTab + (sizeof(DWORD_PTR) * ((4 * n) + 2));
        piid[n].FirstThunk 
= obBase + nOffset;
        pt 
= ((DWORD_PTR*)(pbNew + nOffset));
        pt[
0] = IMAGE_ORDINAL_FLAG + 1;
        pt[
1] = 0;
        piid[n].TimeDateStamp 
= 0;
        piid[n].ForwarderChain 
= 0;
        piid[n].Name 
= obBase + obStr;

        obStr 
+= PadToDword((DWORD)strlen(plpDlls[n]) + 1);
    }


    
// 只是打印出结果
    for (i = 0; i < nDlls + (inh.IMPORT_DIRECTORY.Size / sizeof(*piid)); i++) {
        DETOUR_TRACE((
"%8d. Look=%08x Time=%08x Fore=%08x Name=%08x Addr=%08x ",
                      i,
                      piid[i].OriginalFirstThunk,
                      piid[i].TimeDateStamp,
                      piid[i].ForwarderChain,
                      piid[i].Name,
                      piid[i].FirstThunk));
        
if (piid[i].OriginalFirstThunk == 0 && piid[i].FirstThunk == 0) {
            
break;
        }

    }


    
// 本地配置好了之后写入到远程进程中
    if (!WriteProcessMemory(hProcess, pbNewIid, pbNew, obStr, NULL)) {
        DETOUR_TRACE((
"WriteProcessMemory(iid) failed: %d ", GetLastError()));
        
goto finish;
    }


    DETOUR_TRACE((
"obBase = %p..%p ",
                  inh.IMPORT_DIRECTORY.VirtualAddress,
                  inh.IMPORT_DIRECTORY.VirtualAddress 
+ inh.IMPORT_DIRECTORY.Size));
    DETOUR_TRACE((
"obBase = %p..%p ", obBase, obBase + obStr));

    
// 在本地修改输入表的RVA,之后会写入到远程进程的
    inh.IMPORT_DIRECTORY.VirtualAddress = obBase;
    inh.IMPORT_DIRECTORY.Size 
= cbNew;

    
/////////////////////////////////////////////////// Update the CLR header.
    // 搞不懂为什么要清除 IL_ONLY 标志
    if (inh.CLR_DIRECTORY.VirtualAddress != 0 &&
        inh.CLR_DIRECTORY.Size 
!= 0) {

        DETOUR_CLR_HEADER clr;
        PBYTE pbClr 
= pbModule + inh.CLR_DIRECTORY.VirtualAddress;

        
if (!ReadProcessMemory(hProcess, pbClr, &clr, sizeof(clr), NULL)) {
            DETOUR_TRACE((
"ReadProcessMemory(clr) failed: %d ", GetLastError()));
            
goto finish;
        }


        der.pclrFlags 
= (PULONG)(pbClr + offsetof(DETOUR_CLR_HEADER, Flags));
        der.clrFlags 
= clr.Flags;

        clr.Flags 
&= 0xfffffffe;    // Clear the IL_ONLY flag.

        
if (!VirtualProtectEx(hProcess, pbClr, sizeof(clr), PAGE_READWRITE, &dwProtect)) {
            DETOUR_TRACE((
"VirtualProtextEx(clr) write failed: %d ", GetLastError()));
            
goto finish;
        }


        
if (!WriteProcessMemory(hProcess, pbClr, &clr, sizeof(clr), NULL)) {
            DETOUR_TRACE((
"WriteProcessMemory(clr) failed: %d ", GetLastError()));
            
goto finish;
        }


        
if (!VirtualProtectEx(hProcess, pbClr, sizeof(clr), dwProtect, &dwProtect)) {
            DETOUR_TRACE((
"VirtualProtextEx(clr) restore failed: %d ", GetLastError()));
            
goto finish;
        }

    }


    
/////////////////////// Update the NT header for the import new directory.
    
/////////////////////////////// Update the DOS header to fix the checksum.

    // 修改属性
    if (!VirtualProtectEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
                          PAGE_EXECUTE_READWRITE, 
&dwProtect)) {
        DETOUR_TRACE((
"VirtualProtextEx(inh) write failed: %d ", GetLastError()));
        
goto finish;
    }


    idh.e_res[
0] = 0;
    
// 写入 DOS 头
    if (!WriteProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
        DETOUR_TRACE((
"WriteProcessMemory(idh) failed: %d ", GetLastError()));
        
goto finish;
    }


    
// 写入PE 文件头,IMAGE_NT_HEADER
    if (!WriteProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), NULL)) {
        DETOUR_TRACE((
"WriteProcessMemory(inh) failed: %d ", GetLastError()));
        
goto finish;
    }


    
// 计算效验和 . 搞不懂了,高人来指点
    WORD wDuring = ComputeChkSum(hProcess, pbModule, &inh);
    DETOUR_TRACE((
"ChkSum: %04x + %08x => %08x ", wDuring, dwFileSize, wDuring + dwFileSize));

    idh.e_res[
0] = detour_sum_minus(idh.e_res[0], detour_sum_minus(wDuring, wBefore));

    
if (!WriteProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
        DETOUR_TRACE((
"WriteProcessMemory(idh) failed: %d ", GetLastError()));
        
goto finish;
    }


    
// 修改会原来的属性
    if (!VirtualProtectEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
                          dwProtect, 
&dwProtect)) {
        DETOUR_TRACE((
"VirtualProtextEx(idh) restore failed: %d ", GetLastError()));
        
goto finish;
    }


    
// 最后再次计算效验和,和之前的相比较
    WORD wAfter = ComputeChkSum(hProcess, pbModule, &inh);
    DETOUR_TRACE((
"ChkSum: %04x + %08x => %08x ", wAfter, dwFileSize, wAfter + dwFileSize));
    DETOUR_TRACE((
"Before: %08x, After: %08x ", wBefore + dwFileSize, wAfter + dwFileSize));

    
if (wBefore != wAfter) {
        DETOUR_TRACE((
"Restore of checksum failed %04x != %04x. ", wBefore, wAfter));
        
goto finish;
    }


    
// 没有实际作用的
    if (!DetourCopyPayloadToProcess(hProcess, DETOUR_EXE_RESTORE_GUID, &der, sizeof(der))) {
        DETOUR_TRACE((
"DetourCopyPayloadToProcess failed: %d ", GetLastError()));
        
goto finish;
    }

    

    fSucceeded 
= TRUE;
    
goto finish;
}

一切都尽在注释中了,归纳一下,不外乎这几个步骤:
1. 读出PE头(IMAGE_NT_HEADERS)
2.根据OptionalHeader的DataDirectory找到输入表
3.构造一个新的输入表(这一步是关键)
4.把PE头,以及输入表都写到远程进程去
其他效验和和最后的DetourCopyPayloadToProcess都是后续工作了

[分析]detours 通过修改输入表注入DLL -- UpdateImports 函数的分析 前段时间有一个需求,就是在进程启动的第一时间实现dll的注入,当时一想以为很简单嘛,比如拦截CreateProcessInternalW等不就行了吗?后来发现如果你在CreateProcessInternalW前处理进程还没有启动,而之后处理的话,进程的主线程已经开始工作了,再后来通过修改创建标志把创建的进程的主线程挂起,等进程创建后我来注入,此时才发现创建远线程搞不定, 此时进程只有NTDLL, 阅读详情

相关推荐

windows使用detours实现进程拦截实操

Detours是微软开发的一个函数库,可用于捕获系统API。可以从github下载源码并编译。Detours通过更改被拦截的API函数的跳转地址为用户自定义的函数地址来实现拦截。比如我们知道要拦截API函数A,我们需要自定义一个函数B,在实现拦截之前,此时函数A所在的线程正常调用A。开始拦截的时候,Detours库函数将A的入口地址修改为B的函数指针。此前线程对函数A的调用将会被替换为被函数B的调用,当然前提是函数A和函数B的函数签名完全一致。在将函数A的入口地址修改函数B的地址时已经保留了函数A的原始地址

weixin_38526093的博客 3293

注入小记

DetourCreateProcessWithDll(NULL, (LPWSTR)cmdLine.c_str(), NULL, NULL, FALSE, 0, NULL, (LPCTSTR)gamePath.c_str(), &si, &pi,(LPCTSTR)botPath.c_str(), NULL); +botPath "e:\tiaoshi\TTTTT\hero\src\debug\Im

随心散人专栏 839

Detours注入DLL钩子入门教程

本教程非常初级,适合新手食用 开发环境,WIN10 64bit, VS2022 首先在GITHUB下载源码。GitHub - microsoft/Detours: Detours is a software package for monitoring and instrumenting API calls on Windows. It is distributed in source code form.Detours is a software package for monitor...

DOwnstairs的专栏 5734

PE输入表DLL注入

PE输入表DLL注入

944

DLL注入_修改导入表(1)

PE文件分析 (一) 替换DLL函数 通过修改PE文件导入导出表来更改函数。单纯分析PE文件是一件比较无聊的事,通过修改可以更加灵活的利用和理解PE文件。这就像生活一样,总要有一些特别的事,才能更加有灵感。学习本身就是生活的一部分,如何让程序更加灵活,是一个比较值得去实践的事,可以更加接近计算机的一些思想。 (二) 环境 VC++ 6.0 为了减少复杂度,用VC++ 6.0编译sum.cpp su...

余韵 1639

从零到一:手把手教你用SAM-BA工具完成嵌入式系统烧录

本文详细介绍了如何使用SAM-BA工具完成嵌入式系统烧录的全过程,包括环境搭建、硬件连接、Bootloader烧录以及完整系统镜像的烧录步骤。针对常见问题提供了实用的排查指南,并分享了批量烧录和自定义脚本的高级技巧,帮助开发者高效完成嵌入式系统开发。

weixin_42523792的博客 382

DLL注入-静态修改PE表

首先要知道,我们要完成的操作是通过修改PE结构来完成注入dll,PE中有关于模块导入的是输入表结构,而输入表是一个IID数组,那么想要将我们的dll导入到程序中就需要将一个我们构造的IID结构写入这个数组中,此时需要考虑我们新写入的IID结构大小,假设原IID大小为old,那么显然,由于只导入了一个函数,我们新的IID结构大小newIIDSize = Old+ sizeof(IMAGE_IMPORT_DESCRIPTOR)。将以上各值填入原IID位置,填写的时候需要注意字节序是小端序,填写结果如下。

m0_52164435的博客 1128

海康威视摄像头网线连接笔记本电脑,客户端提示:1连接设备失败。设备不在线或网络原因引起的连接超时等。(HCNetSDK.dll[7].)解决方案

1.环境 电脑:联想笔记本电脑(win10系统) 摄像头:海康威视DS-2CD3T20D-i5,4mm 连接方式:直接用网线将摄像头和摄像头连接 2.问题: 客户端出现如下提示: 3. 解决流程: 1.确认网线是否有问题:我的网线指示灯常亮,并且设备能够被搜索到,只是一直显示离线 2.按照网上教程直接配置摄像头的ip地址与电脑同一网段:登录失败。 错误码为 HCNetSDK.dll[7].(连接设备失败。设备不在【海康威视吧】_百度贴吧 失败了,没有反应 3.查看有线网卡的地

weixin_48911487的博客 3万+

Detours版HOOK 未导出的API函数CreateProcessInternalW

#include <stdio.h> //#include <tchar.h> #include <windows.h> #include "detours.h" #pragma comment(lib,"detours.lib") //以下是HOOK需要的头文件 //#include <winsock2.h> //#include <MSWSock.h> //#pragma comment(lib,"ws2_32.lib") //.

追逐光芒,追随内心 2014

华硕ROG枪神双系统实战:Ubuntu安装避坑指南

本文是华硕ROG枪神笔记本安装Ubuntu双系统的详细避坑指南。针对其独特的硬件与BIOS设计,文章核心解决了VMD控制器导致硬盘无法识别、驱动兼容性等关键难题,并提供了从BIOS设置、分区方案到安装后驱动配置与性能调优的一站式解决方案,帮助用户实现稳定的双系统体验。

raspberrypi5的博客 546

YOLO26涨点改进 | 全网独家复现、小目标检测改进篇 | TGRS 2025 | YOLO26引入MFAE-YOLO中的GFFP、FCPS 和 C3k2-FPEU创新点,涨点起飞,直接发论文

🔥本文给大家介绍在YOLO26中引入MFAE-YOLO中的 GFFP(全局特征融合处理)、FCPS(特征通道像素注意力) 和 C3k2-FPEU(特征池提取单元) 二次创新改进模块,能显著提升对小目标的检测性能。GFFP通过多尺度特征融合增强全局上下文感知能力,有效提升小目标在复杂背景下的可辨性;FCPS融合通道、像素和空间注意力机制,增强了模型对关键细节和小区域特征的关注,提升检测精度;C2F-FPEU利用多种池化方式挖掘细节特征,优化浅层特征表示能力。三者协同提升了YOLO26在小目标检测中的鲁棒性。

Ai缝合怪、助力小伙伴高效发论文 306

PE文件静态注入

点击"蓝字"关注,获取更多技术内容DLL注入指的是向运行中的其他进程强制插入特定的DLL文件。可以通过修改静态的PE文件,修改输入表结构,使得程序执行时载入特定的DLL文件。通常可执行文件...

蚁景网安学院 1487

iOS逆向之深入解析Hook的原理方法和安全防护

Hook简介 Hook就是一种改变程序执行流程的一种技术的统称; 一段程序的执行流程是 A --> B --> C,现在我们在 A 和 B 之间插入一段代码或者直接改变 B ,这样程序原有的执行流程就发生了改变。如下图所示: Hook的方式:Method Swizzle,fishhook,Cydia Substrate; Hook原理 一、Method Swizzle 原理 利用OC的Runtime特性,动态去改变SEL(方法编号)和IMP(方法实现)的对应关系,达到OC方法调用流程改变

╰つ栺尖篴夢ゞ 2万+

Detours Hook 工具源码阅读二

Detours除了提供Hook API,还提供了一些Dll注入的API。文本详细介绍了Detours Create Process & Load Dll 相关的API是如何实现的。

ramonji的博客 936

YOLOv8自定义训练:车牌识别全流程(从标注到推理,附可视化代码)

车牌检测全流程实践指南 摘要:本文详细介绍了基于YOLOv8的车牌检测完整实现方案。针对车牌检测中的三大难点(小目标、多角度、光照变化),提供了从数据准备到模型部署的全流程解决方案。重点包括:1)数据采集与标注规范;2)针对小目标的YOLOv8模型优化配置;3)K-means锚框聚类方法;4)训练参数调优策略。通过实际验证,该方法可获得95%以上的检测准确率,并附有完整的代码实现和可视化工具,便于开发者快速复现应用。 (字数:149字)

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 851

毕业设计:丹麦电力电价预测预测未来24小时的电价pytorch+lstm+历史特征和价格+时间序列 电价预测模型资源 完整代码数据可直接运行

毕业设计:丹麦电力电价预测预测未来24小时的电价pytorch+lstm+历史特征和价格+时间序列 电价预测模型资源 完整代码数据可直接运行

356

记一次挂钩经历

工作中遇到个问题:需要在没有代码的情况下禁用某软件的一个功能。该软件为Windows软件。 接到任务后,先理下思路: ...

yyan的专栏 356

【虚幻引擎UE】UE5 仅需6步轻松实现关卡顺滑切换

【虚幻引擎UE】UE5 仅需6步轻松实现关卡切换

灵境引路人 2万+

PE 通过导入表注入 Dll

导入表注入,当程序被加载时,系统会根据程序导入表信息来加载需要用到的dll,导入表注入的原理就是修改程序的导入表,将自己的dll添加到程序的导入表中,这样程序运行时可以将自己的DLL加载到程序的进程空间。...

多一份贡献,多一份环保 1293

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

DLL 注入的三种方法详解

DLL注入的三种方式

weixin_51409218的博客 5109

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

修改导入表实现DLL注入

Code: [Copy to clipboard]   //// Copy from M

4935

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

注入技术——修改输入表完成DLL注入

参考自《加密与解密》(第4版)第12章 注入技术 实验环境:Windows XP SP2 家庭版 实验素材:作者提供的MsgDLL.dll。此处的待注入DLL使用消息弹框来证明自己注入成功,实际中可以进行各种可怕又邪恶的动作。 修改对象:系统自带记事本 修改目标:记事本启动后,自动加载MsgDLL.dll DLL文件代码细节省略,通过使用MessageBox函数来显示消息框,仅此而已。关于...

不忘初心,护天下安全! 2277

Dll注入:修改PE文件 IAT注入

PE原理就不阐述了, 这个注入是PE感染的一种,通过添加一个新节注入,会改变PE文件的大小,将原有的导入表复制到新节中,并添加自己的导入表描述符,最后将数据目录项中指向的导入表的入口指向新节。步骤:1.添加一个新节;映射PE文件,判断是否可以加一个新节,找到节的尾部,矫正偏移,对齐RVA填充新节PIMAGE_SECTION_HEADER,修改IMAGE_NT_HEADERS,将新节添加到文件尾部 ...

a815064247的博客 1418

无法解析的外部符号 _DetourCreateProcessWithDllW@48,该符号在函数 _WinMain@16 中被引用

最简单的方式来解决,这是的detours.lib复制到项目目录,然后在你的源代码或头文件的任何地方添加一行: #pragma   comment(LIB,“detours.lib”); 如果没有复制到项目目录,我们也可以将“detours.lib”改为“目录+“detours.lib”

自信的尘埃 www.gocpplua.com 2632

使用微软Detours库进行DLL注入

Detours 是微软开发的一个强大的 Windows API 钩子库,用于监视和拦截函数调用。它广泛应用于微软产品团队和众多独立软件开发中,旨在无需修改原始代码的情况下实现函数拦截和修改。本篇文章旨在帮助开发者更好地理解和应用Detours库进行DLL注入操作,从而实现对目标进程的高效控制和管理。无论您是刚接触Detours的新手,还是希望深入了解其高级功能的老手,这篇文章都将提供有价值的参考。

微软技术分享 2255

(二) 使用Detours调试远程线程注入的dll

调试远程线程注入的DLL

Code Captain的专栏 2907
上一篇: 通过PspTerminateThreadByPointer结束进程
下一篇: 开源的Nektra HookLib
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值