объезд перехваченной функции CreateFile вызывает переполнение стека

Когда я пытался использовать Detours для перехвата CreateFile, когда вызывается моя перехваченная функция, я получаю ошибку переполнения стека. Я пытаюсь записать имя файла в файл, а затем вызвать оригинал, но при вызове fopen происходит сбой с ошибкой переполнения стека. Я ввожу dll через вызов CreateRemoteThread. Есть ли какое-то специальное распределение стека, которое мы должны сделать в целевом процессе. Я довольно новичок в разработке 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;
}
*/

person gastromagig    schedule 03.03.2014    source источник


Ответы (1)


Вы заменяете CreateFile своим файлом myCreate. Когда fopen вызывает CreateFile для открытия файла, вместо этого он снова вызывает ваш myCreate, который вызывает fopen, который вызывает CreateFile и так далее, пока у вас не закончится стек. Вы можете вызвать oldCreateFile, чтобы открыть файл для вывода, но вы не сможете использовать с ним fprintf и т.д.

person The Dark    schedule 03.03.2014
comment
Я совершенно не думал об этом. Спасибо за вашу помощь - person gastromagig; 03.03.2014
comment
Могу ли я просто вернуть oldCreate, когда увижу тестовый файл в lpFileName? - person gastromagig; 04.03.2014
comment
Это сработает, вы, вероятно, все равно не хотите регистрировать доступ к этому файлу. Другой вариант — установить логический флаг при входе в функцию myCreate и очистить его при выходе. Затем, если флаг был установлен, не выполняйте регистрацию. Обратите внимание, что это не будет обрабатывать несколько потоков, вам придется использовать локальное хранилище потоков. - person The Dark; 04.03.2014
comment
Знаете ли вы, почему я не мог выполнить простую команду lstrcmp с параметром lpFileName, чтобы проверить, файл это или нет. Он всегда возвращает 1 (ложь). - person gastromagig; 04.03.2014
comment
Я предполагаю, что возможно, что fopen изменяет переданное имя файла. Может быть, он меняет регистр буквы диска или меняет \ на /. Я не могу понять, почему это было бы сделано, хотя. Можете ли вы опубликовать свой новый код? - person The Dark; 04.03.2014
comment
Я понял. Оказывается, я использовал неправильный strcmp, потому что перехватывал createFile, а не createFileW и createFileA. Это работает сейчас - person gastromagig; 06.03.2014