一、前言

钩子技术是一项很有有用价值的技术。在Windows下HOOK技术的方法比較多,使用比較灵活,常见的应用层的HOOK方法有Inline HOOK(详见《反病毒攻防研究第012篇:利用Inline HOOK实现主动防御》)、IAT HOOK、Windows钩子……HOOK技术涉及到了DLL相关的知识(详见《反病毒攻防研究第009篇:DLL注入(上)——DLL文件的编写》)。由于HOOK其它进程的时候须要訪问该进程的地址空间,使用DLL是必定的。HOOK技术也涉及到了注入的知识(详见《反病毒攻防研究第010篇:DLL注入(中)——DLL注入与卸载器的编写》),想要把完毕HOOK功能的DLL载入到目标进程空间中就要使用注入的知识了。而这次令计算器显示汉字,就正是须要使用IAT
HOOK技术,通过DLL注入,来达成目的。

二、IAT HOOK的基本原理

在PE结构的IMAGE_IMPORT_DESCRIPTOR中,有两个IMAGE_THUNK_DATA结构体,第一个为导入名字表,第二个为导入地址表(IAT)。两个结构体在文件其中是没有区别的,可是当PE文件被装载内存后,第二个IMAGE_THUNK_DATA的值会被修正,该值为一个RVA,该RVA加上映像基址后,虚拟地址就保存了真正的导入函数的入口地址。

在这个描写叙述中我们知道,假设想要对IAT进行HOOK,那么大概须要三个步骤,首先是获取要HOOK函数的地址,第二步是找到该函数所保存的IAT中的地址,最后一步是把IAT中的地址改动为HOOK函数的地址,这样就完毕了IAT HOOK。以下举例来说明一下。

比方根据我们这次的目的,想要在计算器中显示汉字,那么根据上一篇文章的分析,我们知道,须要HOOK的模块为user32.dll中的SetWindowTextW()函数,那么首先是获得该函数的地址,第二步是找到SetWindowTextW()所保存的IAT地址,最后一步是把IAT中的SetWindowTextW()函数的地址改动为HOOK函数的地址。

三、IAT HOOK的编码实现

这里依然要建立一个简单的DLL文件,然后定义好DLL文件的主函数,并定义一个hook_iat()函数,在DLL被进程载入的时候,首先保存原始API函数的地址,便于之后的恢复,然后让DLL文件去调用hook_iat()函数;当进程被卸载的时候,利用之前保存的API函数地址,恢复原始状态。代码例如以下:

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch( fdwReason )
{
// 当DLL被某进程载入时DllMain被调用
case DLL_PROCESS_ATTACH :
// 保存原始的API函数地址
g_pOrgFunc = GetProcAddress(GetModuleHandleW(L"user32.dll"),
"SetWindowTextW");
// 运行钩子函数
hook_iat("user32.dll", g_pOrgFunc, (PROC)MySetWindowTextW);
break;
// 当DLL被某进程卸载时DllMain被调用
case DLL_PROCESS_DETACH :
// 解除钩子函数
hook_iat("user32.dll", (PROC)MySetWindowTextW, g_pOrgFunc);
break;
}
return TRUE;
}

在遍历某程序的导入表时是通过文件映射来完毕的,可是当一个可运行文件已经被Windows装载器装载如内存后,就能够省去CreateFile()、CreateFileMapping()等诸多繁琐的步骤(參见《反病毒攻防研究第004篇:利用缝隙实现代码的植入》),取而代之的是通过简单的GetModuleHandle()函数就能够得到exe文件的模块映像地址,并能够非常easy地获取DLL文件导入表的虚拟地址。

整个程序的完整代码例如以下:

#include "stdio.h"
#include "stdafx.h"
#include "wchar.h"
#include "windows.h" typedef BOOL (WINAPI *PFSETWINDOWTEXTW)(HWND hWnd, LPWSTR lpString); FARPROC g_pOrgFunc = NULL; //用于保存原始API函数地址 // SetWindowTextW的钩取函数
BOOL WINAPI MySetWindowTextW(HWND hWnd, LPWSTR lpString)
{
wchar_t* pNum = L"零壹贰叁肆伍陆柒捌玖";
wchar_t temp[2] = {0,};
int i = 0, nLen = 0, nIndex = 0; nLen = wcslen(lpString);
for(i = 0; i < nLen; i++)
{
// 将阿拉伯数字转换为汉字大写形式
// lpString是宽字符版本号(占用两个字节)字符串
if( L'0' <= lpString[i] && lpString[i] <= L'9' )
{
temp[0] = lpString[i];
nIndex = _wtoi(temp);
lpString[i] = pNum[nIndex];
}
} // 字符转换完毕后,再调用SetWindowTextW函数用于显示
return ((PFSETWINDOWTEXTW)g_pOrgFunc)(hWnd, lpString);
} BOOL hook_iat(LPCSTR szDllName, PROC pfnOrg, PROC pfnNew)
{
HMODULE hMod;
LPCSTR szLibName;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
PIMAGE_THUNK_DATA pThunk;
DWORD dwOldProtect, dwRVA;
PBYTE pAddr; // hMod, pAddr = ImageBase of calc.exe
// = VA to MZ signature (IMAGE_DOS_HEADER)
// 获取计算机进程模块基址
hMod = GetModuleHandle(NULL);
pAddr = (PBYTE)hMod;
// pAddr = VA to PE signature (IMAGE_NT_HEADERS)
// 定位PE结构
pAddr += *((DWORD*)&pAddr[0x3C]);
// dwRVA = RVA to IMAGE_IMPORT_DESCRIPTOR Table
dwRVA = *((DWORD*)&pAddr[0x80]); // pImportDesc = VA to IMAGE_IMPORT_DESCRIPTOR Table
pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)hMod+dwRVA); for( ; pImportDesc->Name; pImportDesc++ )
{
// szLibName = VA to IMAGE_IMPORT_DESCRIPTOR.Name
szLibName = (LPCSTR)((DWORD)hMod + pImportDesc->Name);
if( !_stricmp(szLibName, szDllName) )
{
// pThunk = IMAGE_IMPORT_DESCRIPTOR.FirstThunk
// = VA to IAT(Import Address Table)
pThunk = (PIMAGE_THUNK_DATA)((DWORD)hMod +
pImportDesc->FirstThunk); // pThunk->u1.Function = VA to API
for( ; pThunk->u1.Function; pThunk++ )
{
if( pThunk->u1.Function == (DWORD)pfnOrg )
{
// 更改内存属性为PAGE_EXECUTE_READWRITE
VirtualProtect((LPVOID)&pThunk->u1.Function,
4,
PAGE_EXECUTE_READWRITE,
&dwOldProtect); // 改动IAT的值
pThunk->u1.Function = (DWORD)pfnNew; // 恢复内存属性
VirtualProtect((LPVOID)&pThunk->u1.Function,
4,
dwOldProtect,
&dwOldProtect); return TRUE;
}
}
}
}
return FALSE;
}

以上代码已经给出了具体的凝视,代码是对PE文件的基本操作,这里不再赘述。

四、測试程序的效果

将上述程序编译链接成功后,会得到一个DLL文件,使用DLL载入器(详见《反病毒攻防研究第010篇:DLL注入(中)——DLL注入与卸载器的编写》),将这个DLL文件注入到一个计算器程序中,然后按下计算器中的每一个数字,例如以下图所看到的:

图1 注入后的计算器程序

可见我们的程序注入是成功的。

五、小结

利用钩子技术可以实现非常多非常有趣的功能,当然这样的技术不管是在正邪双方面都会被利用到。在此我当然希望各位读者可以善用钩子技术,毕竟假设将这样的思想运用到自己身边的软件中,就会实现非常多非常有意思的效果,丰富我们的生活。须要特别说明的是,假设程序是通过调用LoadLibrary()与GetProcAddress()函数来使用某个函数的话,上面的HOOK代码是无能为力的。要解决这样的问题,就须要对这两个函数也进行HOOK,就行达到目的了。

逆向project第004篇:令计算器程序显示汉字(下)的更多相关文章

  1. 逆向project第003篇:跨越CM4验证机制的鸿沟(上)

    一.前言 <冠军足球经理>系列作为一款拟真度极高的足球经营类游戏.赢得过无数赞誉,而CM4可以说是这个传奇的起点. 可是在游戏安装过程中.当用户输入完序列号之后.程序并不会对用户的输入进行 ...

  2. 逆向project第005篇:跨越CM4验证机制的鸿沟(下)

    一.前言 本文是逆向分析CM4系列的最后一篇,我会将该游戏的序列号验证机制分析完成,进而编写出注冊码生成器. 二.分析第二个验证循环 延续上一篇文章的内容,来到例如以下代码处: 图1 上述代码并没有特 ...

  3. Android 逆向project 实践篇

    Android逆向project 实践篇 上篇给大家介绍的是基础+小Demo实践. 假设没有看过的同学能够进去看看.(逆向project 初篇) 本篇主要给大家介绍怎样反编译后改动源代码, 并打包执行 ...

  4. 逆向project实战--Afkayas.1

    0x00 序言 去年玩了几个月的渗透測试,当初认为非常高端的样子.如今看来只是都是些小把戏,于是開始折腾逆向project. 学习过程中參考的是<逆向project核心原理>这本书.讲的非 ...

  5. zx一篇让Java程序猿随时可以翻看的Oracle总结

    一篇让Java程序猿随时可以翻看的Oracle总结 前言:Oracle学习也有十几天了,但是呢,接下来还要学习许多其他的东西,并不能提步不前,所以在此总结了以下Oracle中常用的命令和语句,没有语法 ...

  6. 单利 复利计算器程序1.0 2.0 3.0 [ 合 ] 之 WEB

    对单复利计算器程序进行改进 更新为网页版的. 界面不太美观 请谅解 由于时间问题暂未完善好! 计算部分的主要源代码:

  7. 纯javascript代码编写计算器程序

    今天来分享一下用纯javascript代码编写的一个计算器程序,很多行业都能用到这个程序,例如做装修预算.贷款利率等等. 首先来看一下完成后的效果: 具体代码如下:(关注我的博客,及时获取最新WEB前 ...

  8. 200行Java代码搞定计算器程序

    发现了大学时候写的计算器小程序,还有个图形界面,能够图形化展示表达式语法树,哈哈;) 只有200行Java代码,不但能够计算加减乘除,还能够匹配小括号~ 代码点评: 从朴素的界面配色到简单易懂错误提示 ...

  9. ROS Learning-018 Arduino-For-ROS-003 (总结篇) 模板程序 即 如何运行

    Arduino For ROS-003 - (总结篇) 模板程序 即 如何运行 我的Ubuntu系统:Ubuntu 14.04.10 TLS 32位 Arduino的版本:Arduino 1.6.11 ...

随机推荐

  1. 一种根据URL参数条件动态生成URL的方法

    最近做了一个产品列表页类似于搜索列表页, 功能比较简单,比搜索页复杂的逻辑在于,生成各个查询条件的URL.我们的链接如下: http://xxx.xxx.xxx/product/list.html?s ...

  2. linux命令行模式下实现代理上网(转)

    有些公司的局域网环境,例如我们公司的只允许使用代理上网,图形界面的很好解决就设置一下浏览器的代理就好了,但是linux纯命令行的界面就....下面简单几步就可以实现了! 一.命令行界面的一般代理设置方 ...

  3. uva 147 Dollars(完全背包)

    题目连接:147 - Dollars 题目大意:有11种硬币, 现在输入一个金额, 输出有多少种组成方案. 解题思路:uva 674 的升级版,思路完全一样, 只要处理一下数值就可以了. #inclu ...

  4. 设置静态IP

    设定IP $sudo vi/etc/network/interfaces autolo iface lo inet loopback 加入下面内容 autoeth0 iface eth0inet st ...

  5. 制作openstack用的centos6.5镜像

    目的: 在centos6.5操作系统环境下制作一个centos6.5的kvm镜像,安装cloud-init,能自己主动扩展根分区 一.制作环境: 操作环境是在openstack平台开一个实例.装的是c ...

  6. 【OpenMesh】Some basic operations: Flipping and collapsing edges

    这一节中你将学到一些OpenMesh中早已提供的基础操作. 内容包括三角形网格边的翻转以及通过连接邻接的顶点边缘折叠. 三角形网格的翻转(Flipping edges) 考虑到两个邻接面的三角形网格中 ...

  7. MFC/VC CxImage 简单配置与使用 (完整版)

    如果本篇文章还不能解决你在生成解决方案以及便宜过程中的问题 请参阅: http://blog.csdn.net/afterwards_/article/details/7997385 我个人配置过来成 ...

  8. JSTL解析——002——core标签库01

    javaEE5之前的版本需要引用JSTL相关的jar包.tld文件等,JAEE5之后就不用这么麻烦了, 如果你的还是不能使用就去官网下载(jstl.jar和standard.jar)这两个jar包,将 ...

  9. Android RingtoneManager铃声管理

    本篇介绍一下跳转到系统铃声选择界面,android中的铃声通过RingtoneManager管理,RingtoneManager管理来电铃声(TYPE_RINGTONE).提示音(TYPE_NOTIF ...

  10. Delaunay三角剖分算法

    在图像处理中,经常会使用到三角剖分算法: 具体定义及其算法可以参考:http://baike.so.com/doc/5447649.html 下面放出来代码: Delaunay接口为存C: 测试是使用 ...