利用detours写了一个工具用于instrument任意指定dll的任意指定函数入口
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
tracebld显示相关进程涉及的文件读写操作
command
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 version="1.0" encoding="UTF-8"?>
-<t:Process xmlns:t="http://schemas.microsoft.com/research/tracebld/2008" exe="notepad" par="" id="::0.::">
<t:Directory>F:\codes\Detours-4.0.1\bin.X86</t:Directory>
<t:Executable>%SYSDIR%\notepad.exe</t:Executable>
<t:Line>%SYSDIR%\notepad.exe </t:Line>
<t:Return>0</t:Return>
-<t:Files>
<t:File write="true" read="true">\\.\NvAdminDevice</t:File>
<t:File read="true">C:\ProgramData\NVIDIA Corporation\Drs\nvdrssel.bin</t:File>
<t:File read="true">C:\ProgramData\NVIDIA Corporation\Drs\nvdrsdb1.bin</t:File>
<t:File read="true">C:\Windows\Fonts\staticcache.dat</t:File>
</t:Files>
<t:Vars> </t:Vars>
</t:Process>
My Instrumentation tool:
配置文件 input.txt
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
测试
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 . . .
输出
'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
核心代码
//dllmain.cpp
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <detours.h>
#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;
}
// injector.cpp
#include <Windows.h>
#include <assert.h>
#include <vector>
#include <algorithm>
#include <detours.h>
#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<Item> 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);
}
利用detours写了一个工具用于instrument任意指定dll的任意指定函数入口的更多相关文章
- 用Java开发一个工具类,提供似于js中eval函数功能的eval方法
今天在看到<Java疯狂讲义>中一个章节习题: 开发一个工具类,该工具类提供一个eval()方法,实现JavaScript中eval()函数的功能--可以动态运行一行或多行程序代码.例如: ...
- 【逆向工具】IDA使用2-VS2015版本release查找main函数入口,局部变量
VS2015版本release查找main函数入口 vc++开发的程序main或WinMain函数是语法规定的用户入口,而不是应用程序入口.入口代码是mainCRTstartup.wmainCRTSt ...
- js 利用throw 写的一个小程序
在下边的小程序中比较特殊的是使用isNaN()函数判断一个参数是不是数字, <!DOCTYPE html> <!DOCTYPE html> <html> <h ...
- 利用PyQt4写的小工具软件
应公司文职工作人员需求,写一个车间人员工作时间的统计软件,输入开始工作时间1,再输入结束工作时间2,计算两个时间的差值. 根据需求,初步构想的UI界面如下: 下面开始干活. 分析后觉得利用PyQt4来 ...
- 利用HttpClient写的一个简单页面获取
之前就听说过利用网络爬虫来获取页面,感觉还挺有意思的,要是能进行一下偏好搜索岂不是可以满足一下窥探欲. 后来从一本书上看到用HttpClient来爬取页面,虽然也有源码,但是也没说用的HttpClie ...
- 利用jquery写的一个TAB页切换效果
函数如下 /** *切换效果 */ function switab(tab,con,tab_c_css,tab_n_css,no) { $(tab).each(function(i){ if(i == ...
- apue编程之参考du代码利用递归写的一个简单的du命令的源代码
#include <stdio.h> #include <stdlib.h> #include <glob.h> #include <string.h> ...
- 访问github太慢?我写了一个开源小工具一键变快
前言 GitHub应该是广大开发者最常去的站点,这里面有大量的优秀项目,是广大开发者寻找资源,交友学习的好地方.尤其是前段时间GitHub公布了一项代码存档计划--Arctic Code Vault, ...
- 利用jdbc简单封装一个小框架(类似DBUtils)
利用jdbc写的一个类似DBUtils的框架 package com.jdbc.orm.dbutils; import java.io.IOException; import java.io.Inpu ...
随机推荐
- PHP控制结构if else,while,do while,for,foreach,break ,continue
php中控制结构有 控制结构 判断分支 if else, 三元运算符, switch case, 循环 while do while for foreach 跳出 break continue // ...
- Hoax or what UVA - 11136(multiset的应用)
刚开始把题意理解错了,结果样例没过,后来发现每天只处理最大和最小的,其余的不管,也就是说昨天的元素会影响今天的最大值和最小值,如果模拟的话明显会超时,故用multiset,另外发现rbegin()的功 ...
- iOS 测试在应用发布前后的痛点探索以及解决方案
作者-芈 峮 前言 iOS 开发从 2010 年开始在国内不断地升温,开发和测试相关的问题不绝于耳.iOS 测试主要涉及哪些内容?又有哪些挑战呢?带着疑问我们开始第一个大问题的讨论. iOS 测试的范 ...
- js 变量以及函数传参
一.变量: 基本类型是变量对象重新创建一个新值给变量对象空间,虽然是同一个值但是互不影响. 引用类型是也是将一个值重新赋值给新的变量空间,但是这个值是堆中对象的一个指针,新的变量和旧的变量指向是同一个 ...
- switch表达式可使用的类型
在java中switch后的表达式的类型只能为以下几种:byte.short.char.int(在Java1.6中是这样),在java1.7后支持了对string的判断.
- 【Selenium-WebDriver实战篇】selenium之使用Tess4J进行验证码图片识别内容
==================================================================================================== ...
- 修改Tomcat启动窗口的名称(Title)
内容简介 有时在运行项目时,在同一服务器会启动多个Tomcat,很难区分某个tomcat运行的是哪个项目,或者想查看tomcat的端口号,只能去server.xml中查看. 如果能把Tomcat窗口的 ...
- LeetCode 801. Minimum Swaps To Make Sequences Increasing
原题链接在这里:https://leetcode.com/problems/minimum-swaps-to-make-sequences-increasing/ 题目: We have two in ...
- 为啥用DTO
0.部分参数对于开发前端的人来说是无意义的,因为传递也没有效果.所以不应该暴露给前端使用. 1.依据现有的类代码,即可方便的构造出DTO对象,而无需重新进行分析. 2.减少请求次数,大大提高效率. 3 ...
- WinDbg常用命令系列---清屏
.cls (Clear Screen) .cls命令清除调试器命令窗口显示. .cls 环境: 模式 用户模式下,内核模式 目标 实时. 崩溃转储 平台 全部 清屏前 清屏后