Skip to content

Instantly share code, notes, and snippets.

@skyclad0x7b7
Last active June 27, 2023 15:52
Show Gist options
  • Save skyclad0x7b7/0b6037e6b3fc64b6b0be4b278eb9add3 to your computer and use it in GitHub Desktop.
Save skyclad0x7b7/0b6037e6b3fc64b6b0be4b278eb9add3 to your computer and use it in GitHub Desktop.
Source code of DLL hooking WriteFile API in Windows x86, x64 Platform
// The MIT License
// Copyright (c) 2019 Sanghyeon Jeon
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "pch.h" // Precompiled Header
#include <stdio.h>
#include <Windows.h>
#pragma pack(push, 1)
struct JMP_5Bytes
{
BYTE opcode; // 0xE9 : Relative Jump
LPVOID lpTarget;
};
struct JMP_6Bytes
{
SHORT opcode; // 0x25FF : Absolute Jump
LPVOID lpTarget;
};
struct JMP_14Bytes // Absolute Jump for 64bit
{
BYTE opcode1; // 0x68 : Push
DWORD lpTarget1; // Address - 4~8
DWORD opcode2; // 0x042444C7 : MOV [ESP+4], ????
DWORD lpTarget2; // Address - 0~4
BYTE opcode3; // 0xC3 : RET
};
#pragma pack(pop)
const char* OrgFP = "\x8B\xFF\x55\x8B\xEC"; // MOV EDI, EDI; PUSH EBP; MOV EBP, ESP;
const char* FPandJmp5Bytes = "\x55\x8B\xEC\xEB\x05"; // PUSH EBP; MOV EBP, ESP; JMP $(Current)+0x5;
typedef BOOL WINAPI tWriteFile(
_In_ HANDLE hFile,
_In_ LPCVOID lpBuffer,
_In_ DWORD nNumberOfBytesToWrite,
_Out_opt_ LPDWORD lpNumberOfBytesWritten,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
#ifdef _WIN64
DWORD WINAPI Hook64();
DWORD WINAPI Unhook64();
#else
DWORD WINAPI Hook32();
DWORD WINAPI Unhook32();
#endif
tWriteFile* newWriteFile;
tWriteFile* orgWriteFile;
JMP_14Bytes orgFP;
BOOL Hooked = FALSE;
BOOL WINAPI NewWriteFile(
_In_ HANDLE hFile,
_In_ LPCVOID lpBuffer,
_In_ DWORD nNumberOfBytesToWrite,
_Out_opt_ LPDWORD lpNumberOfBytesWritten,
_Inout_opt_ LPOVERLAPPED lpOverlapped
)
{
if (nNumberOfBytesToWrite > 0)
MessageBoxA(NULL, (LPCSTR)lpBuffer, NULL, NULL);
#ifdef _WIN64
Unhook64();
BOOL ret = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
Hook64();
#else
Unhook32();
BOOL ret = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
Hook32();
#endif
return ret;
}
DWORD WINAPI Hook32()
{
if (Hooked)
return 0; // Already Hooked
// Get address of target function
LPVOID lpOrgFunc = NULL;
if ((lpOrgFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile")) == NULL)
return -1;
// Check Inline Hook or KernelBase-Redirect-Version Hook
if (*(SHORT*)lpOrgFunc == 0x25FF) // KernelBase-Redirect
{
// Backup old protect
DWORD dwOldProtect;
if (VirtualProtect(lpOrgFunc, sizeof(JMP_6Bytes), PAGE_EXECUTE_READWRITE, &dwOldProtect) == NULL)
return -1;
// Backup old function IAT
JMP_6Bytes * lpSavedFunc = (JMP_6Bytes*)VirtualAlloc(NULL, sizeof(JMP_6Bytes), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
JMP_6Bytes newFuncObj;
memcpy_s(lpSavedFunc, sizeof(JMP_6Bytes), lpOrgFunc, sizeof(JMP_6Bytes));
orgWriteFile = (tWriteFile*)lpSavedFunc->lpTarget;
// Absolute Jump
newFuncObj.opcode = 0x25FF;
// Set new functon to replace
newWriteFile = &NewWriteFile;
newFuncObj.lpTarget = &newWriteFile;
// Replacing
memcpy_s(lpOrgFunc, sizeof(JMP_6Bytes), &newFuncObj, sizeof(JMP_6Bytes));
// Rollback protection
VirtualProtect(lpOrgFunc, sizeof(JMP_6Bytes), dwOldProtect, NULL);
}
else
{ // Inline Hook
orgWriteFile = (tWriteFile*)((DWORD)lpOrgFunc - 5);
// Backup old protect
DWORD dwOldProtect;
if (VirtualProtect((LPVOID)((DWORD)lpOrgFunc - 5), 10, PAGE_EXECUTE_READWRITE, &dwOldProtect) == NULL)
return -1;
JMP_5Bytes newFuncObj;
newFuncObj.opcode = 0xE9; // Relative Jump
newFuncObj.lpTarget = (LPVOID)((DWORD)(&NewWriteFile) - (DWORD)lpOrgFunc - 5); // Set new functon to replace
memcpy_s((LPVOID)((DWORD)lpOrgFunc - 5), 5, FPandJmp5Bytes, 5);// Replacing
memcpy_s(lpOrgFunc, 5, &newFuncObj, 5);
// Rollback protection
VirtualProtect((LPVOID)((DWORD)lpOrgFunc - 5), 10, dwOldProtect, NULL);
}
Hooked = TRUE;
return 0;
}
DWORD WINAPI Unhook32()
{
if (!Hooked)
return 0; // Not Hooked
LPVOID lpOrgFunc = NULL;
if ((lpOrgFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile")) == NULL)
return -1;
// Check Inline Hook or KernelBase-Redirect-Version Hook
if (*(SHORT*)lpOrgFunc == 0x25FF) // KernelBase-Redirect
{
// Backup old protect
DWORD dwOldProtect;
if (VirtualProtect(lpOrgFunc, sizeof(JMP_6Bytes), PAGE_EXECUTE_READWRITE, &dwOldProtect) == NULL)
return -1;
// Set org functon to replace
JMP_6Bytes newFuncObj;
newFuncObj.opcode = 0x25FF;
newFuncObj.lpTarget = orgWriteFile;
// Replacing
memcpy_s(lpOrgFunc, sizeof(JMP_6Bytes), &newFuncObj, sizeof(JMP_6Bytes));
// Rollback protection
VirtualProtect(lpOrgFunc, sizeof(JMP_6Bytes), dwOldProtect, NULL);
}
else
{ // Inline Hook
// Backup old protect
DWORD dwOldProtect;
if (VirtualProtect((LPVOID)((DWORD)lpOrgFunc - 5), 10, PAGE_EXECUTE_READWRITE, &dwOldProtect) == NULL)
return -1;
JMP_5Bytes newFuncObj;
newFuncObj.opcode = 0xE9; // Relative Jump
newFuncObj.lpTarget = (LPVOID)((DWORD)(&NewWriteFile) - (DWORD)lpOrgFunc - 5); // Set new functon to replace
memset((tWriteFile*)((DWORD)lpOrgFunc - 5), 0x90, 5);// Set 5-byte NOP
memcpy_s(lpOrgFunc, 5, OrgFP, 5);
// Rollback protection
VirtualProtect((LPVOID)((DWORD)lpOrgFunc - 5), 10, dwOldProtect, NULL);
}
Hooked = FALSE;
return 0;
}
DWORD WINAPI Hook64()
{
if (Hooked)
return 0; // Already Hooked
// Get address of target function
LPVOID lpOrgFunc = NULL;
if ((lpOrgFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile")) == NULL)
return -1;
// Check KernelBase-Redirect
if (*(SHORT*)lpOrgFunc == 0x25FF)
{
if ((lpOrgFunc = GetProcAddress(GetModuleHandleA("kernelbase.dll"), "WriteFile")) == NULL)
return -1;
}
// Inline Hook
// Backup old protect
DWORD dwOldProtect;
if (VirtualProtect(lpOrgFunc, sizeof(JMP_14Bytes), PAGE_EXECUTE_READWRITE, &dwOldProtect) == NULL)
return -1;
memcpy_s(&orgFP, sizeof(JMP_14Bytes), lpOrgFunc, sizeof(JMP_14Bytes));
JMP_14Bytes newFuncObj;
newFuncObj.opcode1 = 0x68; // Push ????
newFuncObj.lpTarget1 = (DWORD)((DWORD64)(&NewWriteFile) & 0xFFFFFFFF);
newFuncObj.opcode2 = 0x042444C7; // MOV [ESP+4], ????
newFuncObj.lpTarget2 = (DWORD)((DWORD64)(&NewWriteFile) >> 32);
newFuncObj.opcode3 = 0xC3; // RET
memcpy_s(lpOrgFunc, sizeof(JMP_14Bytes), &newFuncObj, sizeof(JMP_14Bytes)); // Replacing
// Rollback protection
VirtualProtect(lpOrgFunc, sizeof(JMP_14Bytes), dwOldProtect, NULL);
Hooked = TRUE;
return 0;
}
DWORD WINAPI Unhook64()
{
if (!Hooked)
return 0; // Not Hooked
LPVOID lpOrgFunc = NULL;
if ((lpOrgFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile")) == NULL)
return -1;
// Check KernelBase-Redirect
if (*(SHORT*)lpOrgFunc == 0x25FF)
{
if ((lpOrgFunc = GetProcAddress(GetModuleHandleA("kernelbase.dll"), "WriteFile")) == NULL)
return -1;
}
// Inline Hook
// Backup old protect
DWORD dwOldProtect;
if (VirtualProtect(lpOrgFunc, sizeof(JMP_14Bytes), PAGE_EXECUTE_READWRITE, &dwOldProtect) == NULL)
return -1;
// reset org FP
memcpy_s(lpOrgFunc, sizeof(JMP_14Bytes), &orgFP, sizeof(JMP_14Bytes));
// Rollback protection
VirtualProtect(lpOrgFunc, sizeof(JMP_14Bytes), dwOldProtect, NULL);
Hooked = FALSE;
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MessageBoxA(NULL, "Hook Ready", "Hook Ready", MB_OK);
#ifdef _WIN64
Hook64();
#else
Hook32();
#endif
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment