您的位置:首页 > 其它

DLL劫持(HiJack)原理以及实现细节

2016-08-21 18:08 239 查看

Dll劫持(HiJack)原理以及实现细节

   
之前就说个要研究一下这个,今天自己尝试了一下,接下来就说下HiJack的原理以及如何实现,至于拿它来做什么,这个...不可描述。

    原理:
这个技术的原理很简单,就是A.exe想要调用B.dll,并且使用里面的FunC函数,这样的话我们把B.Dll改名BB.Dll(有的不用,直接根据路径劫持),然后我们自己写一个B.Dll里面有一个FunC这个函数,然后我们在这个函数里加载BB.Dll,并且调用里面的FunC函数,之后我们在干一些自己的事,对于A.exe来说通常没什么异常感觉,这样我们的目的就达到了,记住此时的你,也就是B.dll的权限和内存归属都是A的,也即是你和A是一家的了,类似于代码注入之后直接修改内存一样。
    原理:上面是最表面的介绍原理,接下来就在编程方面说下原理,因为WIndows上的Dll加载有一个默认的规则,就是先在主程序目录下查找B.dll,如果没有就在系统路径下找,如果还没有,就去环境变量路径里找,就因为这个我们可以轻松的在相应的位置给做劫持,然后问题就如果是实现劫持,就要知道B.Dll里面的所有函数名字以及函数参数,这个地方比较蛋疼,但是也不是绝对不可以实现,分为几种情况,首先就是公用库问题,随便看一下qq的目录:



    看到那个zlib.dll了吗,他是个开源项目,我们可以直接找到源码,然后自己进行编译修改,刚刚我拿了另一个项目的zilb.dll,直接换进去,QQ正常运行了,so...,这个是一种方式,也是最省事的方式,还有一种方式比较麻烦,但是比较通用,就是我们先用CFF
Explorer进行dll的分析,把所有导出函数都拿出来,CFF Explorer是这一款软件:



    安装后显示出来的那个大辣椒,得到dll导出函数时候我们可以直接用IDA去分析这个函数的参数,IDA就是上面大辣椒下面的那个程序,这两个需要自己安装,并且IDA安装的话估计比较蛋疼,直接找小伙伴要吧,还有就是有一点需要说明,IDA的话本身不能完全精准的翻译出来真正的函数参数类型,这个需要结合上下文理解,但是通常参数个数应该是对的,(而且貌似不需要真正的去模拟一定对的参数类型,好像说满足所谓的栈平衡就可以了,这个目前不理解,也不确定)。然后就是我刚刚随便写了一个DLL里面有一个函数是这样:
int Add(int a ,int b ,char c)  然后
CFF Explorer的结果是这样:



然后在IDA上进行分析结果是这样:



    额...显然要结合上下文分析,逆向果真是一个耐心和悟性都要很高才能行的活,之后肯定会学习汇编和逆向相关的东西的再有就是驱动编程,这些都是好东西,但首要当前还是继续学架构和一些其他的东西吧,不管你是搞什么开发,什么方向,架构不行写出来的东西简直就是...,慢慢学一样一样来,都是好东西。
    OK,接下来我就模拟实现一个Dll劫持的全过程。
需要准备的东西
A.exe(自己写的一个,直接调用dll里面Add函数)
B.Dll(这个是A调用的东西)
HiJack.Dll(劫持用的Dll)
 
根据使用的顺序进行编写吧,先来B.Dll
创建一个dll项目,然后添加一个类MyCode里面细节是:
MyCode.h
#pragma once
#ifdef TESTDLL_EXPORTS
#define EXPORTS_DEMO _declspec(dllexport)
#else
#define EXPORTS_DEMO _declspec(dllimport)
#endif
extern "C" EXPORTS_DEMO int Add (int a , int b);

MyCode.cpp
#include "stdafx.h"
#include "MyCode.h"
int Add ( int a , int b)
{
return ( a + b );
}

然后创建使用者A.exe,就是直接调用一下
#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;
typedef int (*AddFunc)(int a, int b);

int main(int argc, _TCHAR* argv[])
{
HMODULE hDll = LoadLibrary(L"B.dll");
if (hDll != NULL)
{
AddFunc add = (AddFunc)GetProcAddress(hDll, "Add");
if (add != NULL)
{
cout<<add(2, 3)<<endl;
}
FreeLibrary(hDll);
}
return 0;
}

    然后再来一个HiJack.Dll 这个里面我就直接默认调用BB.dll,BB.dll就是本身的B.dll,为了不重名真正用的时候会进行改名。(但是如果用的dll不在项目里的话就不用这样了,直接添加B.dll就行,因为dll的查找顺序是先找根目录,我们直接在根目录下放自己的就行了)。实现也是差不多,创建一个dll项目,然后有一个接口,不同的是接口的实现是我们直接载入BB.dll就行。

MyCode.h
#pragma once
#ifdef HIJACK_EXPORTS
#define EXPORTS_DEMO _declspec(dllexport)
#else
#define EXPORTS_DEMO _declspec(dllimport)
#endif
extern "C" EXPORTS_DEMO int Add (int a , int b);

MyCode.Cpp
#include "stdafx.h"
#include "MyCode.h"
#include <iostream>
#include <windows.h>

using namespace std;

typedef int (*AddFunc)(int a, int b);

int Add ( int a , int b)
{
HMODULE hDll = LoadLibrary(L"BB.dll");
if (hDll != NULL)
{
AddFunc add = (AddFunc)GetProcAddress(hDll, "Add");
if (add != NULL)
{
cout<<"HiJack Success"<<endl;
return add(2, 3);
}
FreeLibrary(hDll);
}
}

    上面那个写完之后就可以直接把B.Dll改成BB.Dll,然后把HiJack.Dll改成B.Dll,放在一起,然后执行A.exe发现原来的B.dll被成功劫持。所有的东西都准备好了,我们来简单走一下流程加深理解。
1.首先我们分析下A.exe调用了那些DLL.
现用CFF Explorer 静态分析一次试试



额...结果只是分析出来几个系统的DLL,应该是因为我动态加载的原因或者别的吧,不过没事,
我们可以直接Procmon动态分析:



OK 动态抓到了它加载了B.dll。

2.接下来就分析B.dll的导出函数:
先CFF Explorer



找到导出函数Add,然后我们IDA分析一下B.dll



然后根据上下文分析,这个就看自己逆向能力和经验了,这个我经验不足,就不废话了,分析后确定结果是 int Add(int nA ,int nB)
2.根据分析结果实现HiJack
3.之后我们把A.exe和B.dll(改名BB.dll),HiJack(改名B.dll)放在一起,运行A看效果
注入前执行结果



注入后执行结果:



    OK以上就是HiJack的基本实现,记住先找开源好弄的方式,比如那个zlib或者是导出少的dll等等,这都是简化流程,我上面说的是最最麻烦的那种情况才这么弄。然后我也看了下通常对手是如何防护HiJack的,他们的基本防护大体有两种,第一种是修改dll加载的顺序,就是直接就去系统目录加载,对方认为程序直接去修改系统目录下的dll成功率很低,而且如果装了杀软修改几乎就是不可能的,但是然并卵,因为他们实现这个功能的方式是修改注册表,...你改了,我在劫持前改回来不就得了,可爱的防护思路,还有一种比较绝的方式就是杀软的文件保护的那种方式,这个比较难破,目前不知道。而且告诉一个好消息,除了杀毒软件等特别的保护程序,很少有程序做到了dll保护和验证,因为保护涉及到的东西过于底层,代价比较大,验证的话对升级维护会造成很大麻烦。所以dll劫持目前依然可以横行装逼,让我想起了几乎给赶尽杀绝了的那个洪水DDOS攻击问题,MS已经封闭了伪造IP之后的那个sendto函数,之后会单独再好好说下这几天遇到的DDOS攻击思路和测试结果。

    再补上一张被劫持后的A.exe的动态分析图片(里面可以看到A.exe加载了B.dll,但是BB.dll也被调用,HiJack.dll成功劫持了B.dll)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  DLL劫持 HiJack