detours hooked CreateFile 函数触发堆栈溢出

Posted

技术标签:

【中文标题】detours hooked CreateFile 函数触发堆栈溢出【英文标题】:detours hooked CreateFile function triggers stack overflow 【发布时间】:2014-03-03 05:47:06 【问题描述】:

当我尝试使用 Detours 来挂钩 CreateFile 时,当我的挂钩函数被调用时,我得到一个堆栈溢出错误。我正在尝试将文件名写入文件,然后调用原始文件,但它在 fopen 调用中失败并出现堆栈溢出错误。我通过 CreateRemoteThread 调用注入 dll。在目标进程中我们必须做一些特殊的堆栈分配吗?我对 Windows 开发和弯路相当陌生,但我对 C/C++ 相当了解,但绝不是专家。

#include "stdafx.h"
#include "detours.h"
#include <cstdio>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdio.h>

#pragma comment(lib, "detours.lib")
//#pragma comment(lib, "detoured.lib")
#pragma comment(lib, "ws2_32.lib")


HANDLE (WINAPI *oldCreate)(LPCTSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD,DWORD, HANDLE ) = CreateFile;

HANDLE WINAPI myCreate(LPCTSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD,DWORD,HANDLE); 


INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)

    switch(Reason)
    
        case DLL_PROCESS_ATTACH:
    DetourTransactionBegin();
            DetourUpdateThread(GetCurrentThread());
            DetourAttach(&(PVOID&)oldCreate, myCreate);
            DetourTransactionCommit();
            break;

    case DLL_PROCESS_DETACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    
    return TRUE;


HANDLE WINAPI myCreate(LPCTSTR lpFileName , DWORD dwDesiredAccess, DWORD dwShareMode , LPSECURITY_ATTRIBUTES lpSecurityAttributes  , DWORD dwCreationDisposition ,DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)

    int x= 3;
    FILE *file = fopen("C:\\test.txt", "a+");

    fprintf(file, "%s \n", lpFileName);
    fclose(file);
    return oldCreate(lpFileName,dwDesiredAccess,dwShareMode,lpSecurityAttributes,dwCreationDisposition,dwFlagsAndAttributes,hTemplateFile);




extern "C" __declspec(dllexport) void dummy(void)`enter code here`
    return;

这是我正在使用的注入器代码

另外,这是我正在使用的注入器代码

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include "detours.h"

#pragma comment (lib, "detours.lib")


#define MAX_COMBINED 8192

BOOL SetPrivilege(
    HANDLE hToken,          // token handle
    LPCTSTR Privilege,      // Privilege to enable/disable
    BOOL bEnablePrivilege   // TRUE to enable.  FALSE to disable
    );

LPTSTR GetArguments(void)

    LPWSTR *szArglist = NULL;
    int nArgs;
    LPWSTR  wbuf = NULL;

    wbuf = new WCHAR[MAX_COMBINED];

    if (wbuf == NULL)
        return NULL;

    memset(wbuf, 0, MAX_COMBINED*sizeof(WCHAR));
    szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
    if(NULL == szArglist)
    
        return NULL;
    
    else 
        for(int i=2; i<nArgs; i++) 
            wcscat_s(wbuf, MAX_COMBINED, szArglist[i]);
            wcscat_s(wbuf, MAX_COMBINED, L" ");
        
    
    LocalFree(szArglist);

#ifdef _UNICODE
    return wbuf;
#else
    LPSTR abuf = new CHAR[MAX_COMBINED];

    if (abuf == NULL) 
        return NULL;

    memset(abuf, 0, MAX_COMBINED);
    WideCharToMultiByte(CP_ACP, 0, wbuf, -1, abuf, MAX_COMBINED, NULL, NULL);

    delete[] wbuf;
    return abuf;
#endif


int _tmain(int argc, _TCHAR* argv[])

        HANDLE hToken;
        if(argc < 2)
        
            printf("pass just pid]\n");
            return 0;
        
        char* DirPath = new char[MAX_PATH];
        char* FullPath = new char[MAX_PATH];
        GetCurrentDirectoryA(MAX_PATH, (LPSTR)DirPath);
        sprintf_s(FullPath, MAX_PATH, "%s\\injector3.dll", DirPath);
        printf("FullPath %s \n",FullPath);
        if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken))
        
            if (GetLastError() == ERROR_NO_TOKEN)
            
                if (!ImpersonateSelf(SecurityImpersonation))
                return 1;

                if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken))
                    printf("OpenThreadToken\n");
                    return 1;
                
            
            else
                return 1;
        

    // enable SeDebugPrivilege
        if(!SetPrivilege(hToken, SE_DEBUG_NAME, TRUE))
        
            printf("SetPrivilege");

            // close token handle
            CloseHandle(hToken);

            // indicate failure
            return 2;
        

        HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD    | PROCESS_VM_OPERATION    |
            PROCESS_VM_WRITE, FALSE, _wtoi(argv[1]));
        if(hProcess == NULL)
        
            DWORD x =  GetLastError();
            printf("HANDLE TO PROCESS FAILED on PID %d with error %d\n",_wtoi(argv[1]),x);

            return 1;
        
        LPVOID LoadLibraryAddr = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"),
            "LoadLibraryA");
        if(LoadLibraryAddr == NULL)
        
            printf("GET PROC ADDRESS FAILED on PID %s\n",argv[1]);
            return 1;
        
        LPVOID LLParam = (LPVOID)VirtualAllocEx(hProcess, NULL, strlen(FullPath),
            MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
        if(LLParam == NULL)
        
            printf("VirtualAllocEx on PID %s\n",argv[1]);
            return 1;
        
        WriteProcessMemory(hProcess, LLParam, FullPath, strlen(FullPath), NULL);
        CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryAddr,
            LLParam, NULL, NULL);
        CloseHandle(hProcess);
        delete [] DirPath;
        delete [] FullPath;


BOOL SetPrivilege(
    HANDLE hToken,          // token handle
    LPCTSTR Privilege,      // Privilege to enable/disable
    BOOL bEnablePrivilege   // TRUE to enable.  FALSE to disable
    )

    TOKEN_PRIVILEGES tp;
    LUID luid;
    TOKEN_PRIVILEGES tpPrevious;
    DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);

    if(!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE;

    // 
    // first pass.  get current privilege setting
    // 
    tp.PrivilegeCount           = 1;
    tp.Privileges[0].Luid       = luid;
    tp.Privileges[0].Attributes = 0;

    AdjustTokenPrivileges(
            hToken,
            FALSE,
            &tp,
            sizeof(TOKEN_PRIVILEGES),
            &tpPrevious,
            &cbPrevious
            );

    if (GetLastError() != ERROR_SUCCESS) return FALSE;

    // 
    // second pass.  set privilege based on previous setting
    // 
    tpPrevious.PrivilegeCount       = 1;
    tpPrevious.Privileges[0].Luid   = luid;

    if(bEnablePrivilege) 
        tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
    
    else 
        tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
            tpPrevious.Privileges[0].Attributes);
    

    AdjustTokenPrivileges(
            hToken,
            FALSE,
            &tpPrevious,
            cbPrevious,
            NULL,
            NULL
            );

    if (GetLastError() != ERROR_SUCCESS) return FALSE;

    return TRUE;

/*
BOOL SetPrivilege( 
    HANDLE hToken,  // token handle 
    LPCTSTR Privilege,  // Privilege to enable/disable 
    BOOL bEnablePrivilege  // TRUE to enable. FALSE to disable 
) 
 
    TOKEN_PRIVILEGES tp =  0 ; 
    // Initialize everything to zero 
    LUID luid; 
    DWORD cb=sizeof(TOKEN_PRIVILEGES); 
    if(!LookupPrivilegeValue( NULL, Privilege, &luid ))
        return FALSE; 
    tp.PrivilegeCount = 1; 
    tp.Privileges[0].Luid = luid; 
    if(bEnablePrivilege)  
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
     else  
        tp.Privileges[0].Attributes = 0; 
     
    AdjustTokenPrivileges( hToken, FALSE, &tp, cb, NULL, NULL ); 
    if (GetLastError() != ERROR_SUCCESS) 
        return FALSE; 

    return TRUE;

*/

【问题讨论】:

【参考方案1】:

您正在用您的 myCreate 替换 CreateFile。 当 fopen 调用 CreateFile 打开文件时,它会再次调用你的 myCreate,这将调用 fopen,它将调用 CreateFile 等等,直到你用完堆栈。 您可以调用 oldCreateFile 来打开文件进行输出,但您将无法使用 fprintf 等。

【讨论】:

我完全没有想到这一点。感谢您的帮助 当我在 lpFileName 中看到测试文件时,我可以只返回 oldCreate 吗? 这行得通,你可能不想记录对该文件的访问。另一种选择是在您输入 myCreate 函数时设置一个布尔标志,并在您离开时清除它。然后,如果设置了标志,则不要进行日志记录。请注意,这不会处理多个线程,您必须使用线程本地存储。 你知道为什么我不能用 lpFileName 做一个简单的 lstrcmp 来检查它是否是文件。它总是返回 1 (false)。 我猜fopen可能会更改传入的文件名。也许它会更改驱动器号的大小写或将\更改为/。我想不出它为什么会那样做。你能发布你的新代码吗?

以上是关于detours hooked CreateFile 函数触发堆栈溢出的主要内容,如果未能解决你的问题,请参考以下文章

Detours Hook:GetVolumeInformation 随机卷序列

Detours简介 (拦截x86机器上的任意的win32 API函数)

Microsoft Detour - 带有汇编程序“调用”指令的挂钩函数

Delphi Detours Library

Hook CreateProcess

Linux Ubuntu下的绕行功能