利用detours写了一个工具用于instrument任意指定dll的任意指定函数入口.
[TOC]
# wiki
https://github.com/microsoft/Detours/wiki
# Disas
Tests the Detours disassembler tables.
Uses
DetourEnumerateExports, DetourEnumerateModules, DetourGetEntryPoint, DetourGetModuleSize.
# Dtest
Detours the Win32 Sleep function and a private function. The private function is first detoured, then detoured recursively 3 times using the DetourAttach API.
Uses
DetourAttach, DetourTransactionBegin, DetourTransactionCommit, DetourUpdateThread.
# Simple
detour to modify the Windows Sleep API.
# withdll load一个dll到指定进程
The withdll.exe program include in the Detours package uses the DetourCreateProcessWithDlls API to start a new process with a named DLL.
example of withdll
![1570716876227](C:\Users\cutep\AppData\Roaming\Typora\typora-user-images\1570716876227.png)
# tracebld显示相关进程涉及的文件读写操作
command
```python
F:\codes\Detours-4.0.1\bin.X86>tracebld.exe /o:1.txt notepad
TRACEBLD: Ready for clients. Press Ctrl-C to stop.
TRACEBLD: Starting: `notepad'
TRACEBLD: with `F:\codes\Detours-4.0.1\bin.X86\trcbld32.dll'
TRACEBLD: 1 processes.
```
output file
```xml
-
F:\codes\Detours-4.0.1\bin.X86
%SYSDIR%\notepad.exe
%SYSDIR%\notepad.exe
0
-
\\.\NvAdminDevice
C:\ProgramData\NVIDIA Corporation\Drs\nvdrssel.bin
C:\ProgramData\NVIDIA Corporation\Drs\nvdrsdb1.bin
C:\Windows\Fonts\staticcache.dat
```
# My Instrumentation tool:
配置文件 input.txt
```python
dll=kernel32.dll fun=OpenFile
dll=user32.dll fun=MessageBoxA
dll=user32.dll fun=MessageBoxW
dll=user32.dll fun=OffsetRect
dll=kernel32.dll fun=WaitForSingleObject
dll=kernel32.dll fun=CloseHandle
```
测试
```python
F:\codes\Detours-4.0.1\bin.X86>withdll.exe /d:C:\Users\cutep\source\repos\ConsoleApplication1\Debug\dll1.dll notepad
Press any key to continue . . .
withdll.exe: Starting: `notepad'
withdll.exe: with `C:\Users\cutep\source\repos\ConsoleApplication1\Debug\dll1.dll'
Resume Thread...
Press any key to continue . . .
```
输出
```python
'notepad.exe' (Win32): Loaded 'C:\Windows\syswow64\notepad.exe'. Cannot find or open the PDB file.
...
'notepad.exe' (Win32): Loaded 'C:\Users\cutep\source\repos\ConsoleApplication1\Debug\Dll1.dll'. Symbols loaded.
...
processing line: dll=kernel32.dll fun=OpenFile
processing line: dll=user32.dll fun=MessageBoxA
processing line: dll=user32.dll fun=MessageBoxW
processing line: dll=user32.dll fun=OffsetRect
processing line: dll=kernel32.dll fun=WaitForSingleObject
processing line: dll=kernel32.dll fun=CloseHandle
processing line:
>>dll=kernel32.dll fun=WaitForSingleObject
>>dll=kernel32.dll fun=CloseHandle
.....
>>dll=user32.dll fun=OffsetRect
>>dll=user32.dll fun=OffsetRect
...
>>dll=kernel32.dll fun=CloseHandle
Exception thrown at 0x0FF81BCC (ucrtbased.dll) in notepad.exe: 0xC0000005: Access violation reading location 0xFEEEFEEE.
The program '[0x1DE0] notepad.exe' has exited with code 0 (0x0).
```
link: https://files.cnblogs.com/files/cutepig/ConsoleApplication1.7z
核心代码
```cpp
//dllmain.cpp
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include
#include "../Injector.h"
Injector gInj;
static int (WINAPI * TrueEntryPoint)(VOID) = NULL;
static int (WINAPI * RawEntryPoint)(VOID) = NULL;
static void DebugStr(const char *fmt, ...)
{
va_list l;
va_start(l, fmt);
char s[100];
vsnprintf(s, 100, fmt, l);
printf(s);
OutputDebugStringA(s);
}
int WINAPI TimedEntryPoint(VOID)
{
FILE *fp = fopen("input.txt", "r");
if (!fp)
{
DebugStr("Open file fails");
return -1;
}
char s[300];
while (fgets(s, 300, fp))
{
DebugStr("processing line: %s", s);
char dll[100];
char fun[100];
if (2 != sscanf(s, "dll=%s fun=%s", dll, fun))
{
DebugStr("Error scanf from line: %s", s);
continue;
}
PVOID pFun = DetourFindFunction(dll, fun);
if (!pFun)
{
DebugStr("Error DetourFindFunction from line: %s %s", dll, fun);
continue;
}
gInj.Inject(pFun, s);
}
return TrueEntryPoint();
}
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
LONG error;
(void)hinst;
(void)reserved;
if (DetourIsHelperProcess()) {
return TRUE;
}
if (dwReason == DLL_PROCESS_ATTACH) {
DetourRestoreAfterWith();
// NB: DllMain can't call LoadLibrary, so we hook the app entry point.
TrueEntryPoint = (int (WINAPI *)(VOID))DetourGetEntryPoint(NULL);
RawEntryPoint = TrueEntryPoint;
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)TrueEntryPoint, TimedEntryPoint);
error = DetourTransactionCommit();
if (error == NO_ERROR) {
printf("dslept" DETOURS_STRINGIFY(DETOURS_BITS) ".dll: "
" Detoured EntryPoint().\n");
}
else {
printf("dslept" DETOURS_STRINGIFY(DETOURS_BITS) ".dll: "
" Error detouring EntryPoint(): %d\n", error);
}
}
else if (dwReason == DLL_PROCESS_DETACH) {
}
return TRUE;
}
```
```cpp
// injector.cpp
#include
#include
#include
#include
#include
#include "Injector.h"
void GenCode(char *&p, int n, const char *data)
{
//std::copy(data, data + n, p);
memcpy(p, data, n);
p += n;
}
void GenAddEsp4(char *&p)
{
char data[3] = { 0x83, 0xC4, 0x04 };
GenCode(p, 3, data);
}
void GenPushPtr(char *&p, void const *pData)
{
char *pcoffset = (char *)&pData;
char data[5] = { 0x68, pcoffset[0], pcoffset[1], pcoffset[2], pcoffset[3] };
GenCode(p, 5, data);
}
void GenCall(char *&p, void const *pFn)
{
DWORD offset = (DWORD)pFn - ((DWORD)p + 5);
char *pcoffset = (char *)&offset;
char data[5] = { 0xe8, pcoffset[0], pcoffset[1], pcoffset[2], pcoffset[3] };
GenCode(p, 5, data);
}
void GenJump(char *&p, void const *pFn)
{
DWORD offset = (DWORD)pFn - ((DWORD)p + 5);
char *pcoffset = (char *)&offset;
char data[5] = { 0xe9, pcoffset[0], pcoffset[1], pcoffset[2], pcoffset[3] };
GenCode(p, 5, data);
}
class InjectorImpl
{
struct Code {
char* adr;
char* codeOfJump;
Code() :adr(0), codeOfJump(0)
{}
};
struct Item {
std::string desc;
void const *fOriginal;
void *fTramper; // the original function is changed to tramper after inject
Code code;
char *codeOfJump; // ptr pointer to jump. It shoulod be updated after Submit
Item():fOriginal(0), fTramper(0), codeOfJump(0)
{}
};
std::vector- mvItems;
static void MyInstrument(Item *item)
{
char s[100];
_snprintf_s(s, 100, ">>%s\n", item->desc.c_str());
printf(s);
OutputDebugStringA(s);
}
static Code GenInjectCodePart1(Item const *item)
{
int size = 100;
char *adr = (char*)VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
Code code;
code.adr = adr;
// write code to the region
char *p = adr;
// Call Instrument("hello")
GenPushPtr(p, item);
GenCall(p, MyInstrument);
GenAddEsp4(p);
// call test()
//GenCall(p, Test);
// Jump to Add()
code.codeOfJump = p;
return code;
}
static void GenInjectCodePart2(Item const *item)
{
int size = 100;
assert(item->fTramper != item->fOriginal);
char *p = item->code.codeOfJump;
GenJump(p, item->fTramper);
// Set as executable
DWORD oldProtection;
BOOL ok = VirtualProtect(item->code.adr, size, PAGE_EXECUTE_READ, &oldProtection);
assert(ok);
FlushInstructionCache(GetCurrentProcess(), item->code.adr, size);
}
void FreeInjectCode(char* adr)
{
VirtualFree(adr, 0, MEM_RELEASE);
}
public:
InjectorImpl()
{
mvItems.reserve(100);
}
~InjectorImpl()
{}
void Inject(void const *f, char const *desc)
{
assert(mvItems.size() < mvItems.capacity());
mvItems.push_back(Item());
Item &item = mvItems.back();
item.fOriginal = item.fTramper = (void*)f;
item.desc = desc;
Code code = GenInjectCodePart1(&item);
item.code = code;
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)item.fTramper, item.code.adr);
DetourTransactionCommit();
GenInjectCodePart2(&item);
}
//void Test()
//{
// Item item;
// item.fOriginal = item.fTramper = (void*)Add;
// item.desc = "desc";
// Code code = GenInjectCodePart1(&item);
// item.code = code;
// GenInjectCodePart2(&item);
// int(*pAdd)(int a, int b) = (int(*)(int a, int b))item.code.adr;
// assert(pAdd(1, 2) == 3);
//}
private:
};
// Injector
/////////////////////
Injector::Injector():impl(new InjectorImpl)
{
}
Injector::~Injector(){}
void Injector::Inject(void const *f, char const *desc)
{
impl->Inject(f, desc);
}
```