兼容32位和64位的劫持DLL方案

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/aqtata/article/details/79118248

编写一个劫持DLL并不难,无非就是模拟原DLL导出其所有的函数,在假的函数内call/jmp到真的函数即可。现在的问题就在于DLL内是用call还是jmp?

如果用call的话,你得需要知道每一个函数的参数以及调用方式,这样代码量会比较多,最重要的是微软有很多未公开的函数,这就更麻烦了。。。这个方案唯一的好处是同时支持x86和x64。

如果用jmp的话,好处就是不用理会原函数的调用方式以及参数,相对于使用call的方案这是非常省心的一件事。坏处就是得使用内联汇编,因为为了让原参数顺利达到真正的函数,中间函数不能有任何多余的汇编代码,所以就需要这样写

void __declspec(naked) Foo()
{
	__asm jmp OldFun
}
可是,vc编译器并不支持64位的内联汇编(如果支持的话就不会有此文了)。网上搜了一圈,比较简单的解决方案就是换成Intel的编译器,因为他家的编译器支持x64内联汇编,但这个东西似乎是收费的,而且Windows平台最好还是用微软自家的编译器最好,所以这个方案可以否定了。


另一个方案也就是最终方案,在工程内引入asm文件(https://www.cnblogs.com/achillis/p/5369658.html),把汇编写到这里而不是使用内联汇编,这样就能使用jmp的方式劫持并同时支持32位和64位了。提醒一下,x64用ml64.exe,而x86用ml.exe。

比如我劫持的version.dll,x86.asm文件内容如下

.MODEL flat,stdcall

extern g_pfnGetFileVersionInfoA: DWORD
extern g_pfnGetFileVersionInfoByHandle: DWORD
extern g_pfnGetFileVersionInfoExW: DWORD
extern g_pfnGetFileVersionInfoSizeA: DWORD
extern g_pfnGetFileVersionInfoSizeExW: DWORD
extern g_pfnGetFileVersionInfoSizeW: DWORD
extern g_pfnGetFileVersionInfoW: DWORD
extern g_pfnVerFindFileA: DWORD
extern g_pfnVerFindFileW: DWORD
extern g_pfnVerInstallFileA: DWORD
extern g_pfnVerInstallFileW: DWORD
extern g_pfnVerLanguageNameA: DWORD
extern g_pfnVerLanguageNameW: DWORD
extern g_pfnVerQueryValueA: DWORD
extern g_pfnVerQueryValueW: DWORD

.code

FakeGetFileVersionInfoA proc
  jmp g_pfnGetFileVersionInfoA
FakeGetFileVersionInfoA endp

FakeGetFileVersionInfoByHandle proc
  jmp g_pfnGetFileVersionInfoByHandle
FakeGetFileVersionInfoByHandle endp

FakeGetFileVersionInfoExW proc
  jmp g_pfnGetFileVersionInfoExW
FakeGetFileVersionInfoExW endp

FakeGetFileVersionInfoSizeA proc
  jmp g_pfnGetFileVersionInfoSizeA
FakeGetFileVersionInfoSizeA endp

FakeGetFileVersionInfoSizeExW proc
  jmp g_pfnGetFileVersionInfoSizeExW
FakeGetFileVersionInfoSizeExW endp

FakeGetFileVersionInfoSizeW proc
  jmp g_pfnGetFileVersionInfoSizeW
FakeGetFileVersionInfoSizeW endp

FakeGetFileVersionInfoW proc
  jmp g_pfnGetFileVersionInfoW
FakeGetFileVersionInfoW endp

FakeVerFindFileA proc
  jmp g_pfnVerFindFileA
FakeVerFindFileA endp

FakeVerFindFileW proc
  jmp g_pfnVerFindFileW
FakeVerFindFileW endp

FakeVerInstallFileA proc
  jmp g_pfnVerInstallFileA
FakeVerInstallFileA endp

FakeVerInstallFileW proc
  jmp g_pfnVerInstallFileW
FakeVerInstallFileW endp

FakeVerLanguageNameA proc
  jmp g_pfnVerLanguageNameA
FakeVerLanguageNameA endp

FakeVerLanguageNameW proc
  jmp g_pfnVerLanguageNameW
FakeVerLanguageNameW endp

FakeVerQueryValueA proc
  jmp g_pfnVerQueryValueA
FakeVerQueryValueA endp

FakeVerQueryValueW proc
  jmp g_pfnVerQueryValueW
FakeVerQueryValueW endp

end
x64.asm也基本相同

extern g_pfnGetFileVersionInfoA: DQ
extern g_pfnGetFileVersionInfoByHandle: DQ
extern g_pfnGetFileVersionInfoExW: DQ
extern g_pfnGetFileVersionInfoSizeA: DQ
extern g_pfnGetFileVersionInfoSizeExW: DQ
extern g_pfnGetFileVersionInfoSizeW: DQ
extern g_pfnGetFileVersionInfoW: DQ
extern g_pfnVerFindFileA: DQ
extern g_pfnVerFindFileW: DQ
extern g_pfnVerInstallFileA: DQ
extern g_pfnVerInstallFileW: DQ
extern g_pfnVerLanguageNameA: DQ
extern g_pfnVerLanguageNameW: DQ
extern g_pfnVerQueryValueA: DQ
extern g_pfnVerQueryValueW: DQ

.code

FakeGetFileVersionInfoA proc
  jmp g_pfnGetFileVersionInfoA
FakeGetFileVersionInfoA endp

FakeGetFileVersionInfoByHandle proc
  jmp g_pfnGetFileVersionInfoByHandle
FakeGetFileVersionInfoByHandle endp

FakeGetFileVersionInfoExW proc
  jmp g_pfnGetFileVersionInfoExW
FakeGetFileVersionInfoExW endp

FakeGetFileVersionInfoSizeA proc
  jmp g_pfnGetFileVersionInfoSizeA
FakeGetFileVersionInfoSizeA endp

FakeGetFileVersionInfoSizeExW proc
  jmp g_pfnGetFileVersionInfoSizeExW
FakeGetFileVersionInfoSizeExW endp

FakeGetFileVersionInfoSizeW proc
  jmp g_pfnGetFileVersionInfoSizeW
FakeGetFileVersionInfoSizeW endp

FakeGetFileVersionInfoW proc
  jmp g_pfnGetFileVersionInfoW
FakeGetFileVersionInfoW endp

FakeVerFindFileA proc
  jmp g_pfnVerFindFileA
FakeVerFindFileA endp

FakeVerFindFileW proc
  jmp g_pfnVerFindFileW
FakeVerFindFileW endp

FakeVerInstallFileA proc
  jmp g_pfnVerInstallFileA
FakeVerInstallFileA endp

FakeVerInstallFileW proc
  jmp g_pfnVerInstallFileW
FakeVerInstallFileW endp

FakeVerLanguageNameA proc
  jmp g_pfnVerLanguageNameA
FakeVerLanguageNameA endp

FakeVerLanguageNameW proc
  jmp g_pfnVerLanguageNameW
FakeVerLanguageNameW endp

FakeVerQueryValueA proc
  jmp g_pfnVerQueryValueA
FakeVerQueryValueA endp

FakeVerQueryValueW proc
  jmp g_pfnVerQueryValueW
FakeVerQueryValueW endp

end
汇编代码中引用了全局变量,也就是真实函数地址,在c++文件中声明

#pragma once

#include <Windows.h>

EXTERN_C FARPROC g_pfnGetFileVersionInfoA;
EXTERN_C FARPROC g_pfnGetFileVersionInfoByHandle;
EXTERN_C FARPROC g_pfnGetFileVersionInfoExW;
EXTERN_C FARPROC g_pfnGetFileVersionInfoSizeA;
EXTERN_C FARPROC g_pfnGetFileVersionInfoSizeExW;
EXTERN_C FARPROC g_pfnGetFileVersionInfoSizeW;
EXTERN_C FARPROC g_pfnGetFileVersionInfoW;
EXTERN_C FARPROC g_pfnVerFindFileA;
EXTERN_C FARPROC g_pfnVerFindFileW;
EXTERN_C FARPROC g_pfnVerInstallFileA;
EXTERN_C FARPROC g_pfnVerInstallFileW;
EXTERN_C FARPROC g_pfnVerLanguageNameA;
EXTERN_C FARPROC g_pfnVerLanguageNameW;
EXTERN_C FARPROC g_pfnVerQueryValueA;
EXTERN_C FARPROC g_pfnVerQueryValueW;
这些变量在DLL加载时通过GetProcAddress赋值即可。

最后,在工程中新建一个导出声明文件,内容如下

LIBRARY
EXPORTS
GetFileVersionInfoA=FakeGetFileVersionInfoA @1
GetFileVersionInfoByHandle=FakeGetFileVersionInfoByHandle @2
GetFileVersionInfoExW=FakeGetFileVersionInfoExW @3
GetFileVersionInfoSizeA=FakeGetFileVersionInfoSizeA @4
GetFileVersionInfoSizeExW=FakeGetFileVersionInfoSizeExW @5
GetFileVersionInfoSizeW=FakeGetFileVersionInfoSizeW @6
GetFileVersionInfoW=FakeGetFileVersionInfoW @7
VerFindFileA=FakeVerFindFileA @8
VerFindFileW=FakeVerFindFileW @9
VerInstallFileA=FakeVerInstallFileA @10
VerInstallFileW=FakeVerInstallFileW @11
VerLanguageNameA=FakeVerLanguageNameA @12
VerLanguageNameW=FakeVerLanguageNameW @13
VerQueryValueA=FakeVerQueryValueA @14
VerQueryValueW=FakeVerQueryValueW @15
可以看到,这样的写法完全不理会函数调用方式及参数,还能支持x64,完美。


猜你喜欢

转载自blog.csdn.net/aqtata/article/details/79118248