上一篇文章介绍了“TabSiPlus”是如何进行代码注入的,本篇将介绍如何构建一个外挂软件最重要的部分,也就是为其扩展功能的定制代码。本文前面提到过,由于windows进程管理的限制,扩展代码必须以动态链接库的形式挂载到被挂程序的进程空间中,使用上一篇介绍的方法已经可以通过创建远程线程的方式启动一个线程,让这个线程加载我们的定制动态链接库,现在就看看这个动态链接库是如何实现的。

首先这是一个动态链接库,因为考虑到扩展功能中有大量的界面操作,所以选择支持MFC,同时,还要提供一个名为“InitFunc”的导出函数,供在被挂程序中启动的远程线程调用,以初始化外挂动态链接库,这个导出函数的原型是这样的:
typedef DWORD (WINAPI *PFN)();
没有参数,但是有一个返回值用于表示初始化是否成功。现在就用Visual C++的向导生成一个支持MFC的动态链接库的框架,并手工添加一个名为“InitFunc”的导出函数,如果你还不清楚怎么做,那么可以停止看本文了,因为本文可能对你毫无用处。
  
    在生成的代码中,MFC对DllMain进行了封装,所以有了一个CxxxApp的类,xxx与你的动态链接库的名字一致,TabSiPlus使用的是CTabSiPlusApp,现在有三个地方需要特别注意,一个是CTabSiPlusApp::InitInstance(),一个是CTabSiPlusApp::ExitInstance(),另一个就是我们的导出函数“InitFunc”。当远程线程中LoadLibrary()调用我们的定制动态链接库时,CTabSiPlusApp::InitInstance()被调用,当FreeLibrary()调用发生时,CTabSiPlusApp::ExitInstance()被调用,当然,伴随而出现的还有两个函数调用,那就是CTabSiPlusApp类的构造函数和析构函数,部分初始化代码也可以放在构造函数中完成,不过并不推荐这样做,因为如果因为构造函数触发异常导致LoadLibrary()失败,那么随后的析构函数也不会被调用,因为构造函数没有完成对象的构造,同时,由于LoadLibrary()失败,使得FreeLibrary()调用分支没有执行,那么导致CTabSiPlusApp::ExitInstance()也没有被调用,这会引起资源释放的异常。

很显然,CTabSiPlusApp::InitInstance()的调用发生在InitFunc函数的调用之前,所以要控制好初始化代码之前的先后关系。CTabSiPlusApp::InitInstance()中布置对资源初始化的代码,而诸如创建文件标签栏窗口,Hook “Source Insight”窗口消息,管理这些消息的代码则可以布置到InitFunc函数中实现。这里需要注意的是由于我们的外挂代码是以动态链接库的形式挂载到“Source Insight”进程中的,所以它没有消息循环,所有的窗口UI系统无法正常工作,解决的办法有两个,一个是在InitFunc函数创建窗口之后人为地添加一个消息循环,关于这一点如何实现可以参考Windows SDK编程的方法;另一个方法就是不要把主要的工作放在InitFunc,而是在InitFunc函数中再创建一个本地线程,把窗口UI这些麻烦的东西放在这个线程中处理,这样就可以利用这个线程的消息循环使窗口UI系统工作起来,这样做还有一个好处,就是InitFunc函数可以立即返回,加载外挂的宿主程序也可以及时得到外挂的加载情况,以便根据情况安排下一次加载动作(就是调用CreateRemoteThread()),同时还可以及时释放在被挂程序中分配的内存。TabSiPlus就是采用的第二种方法,下面就是TabSiPlus的InitFunc函数实现,当然省去了一些代码,主要核心就是一行:

DWORD WINAPI InitFunc()
{
    //其它初始化操作
    g_pTabWndUIThread = (CTabWndUIThread *)AfxBeginThread(RUNTIME_CLASS(CTabWndUIThread),THREAD_PRIORITY_NORMAL,0,0,NULL);
    //其它操作
    
    return (g_pTabWndUIThread != NULL);
}

在CTabWndUIThread类的InitInstance()函数中创建标签栏窗口,hook “Source Insight”中相关窗口的消息:

BOOL CTabWndUIThread::InitInstance()
{
  AFX_MANAGE_STATE(AfxGetStaticModuleState());

g_pSiFrameWnd = new CSIFrameWnd(); //CWnd::FromHandle(hDevStudioWnd);
  g_pSiFrameWnd->Attach(hWndSIFrame); //hook SI主窗口

HWND hMDIWnd = g_pSiFrameWnd->GetMDIClientWnd();
    
    //UINT uThressID = GetCurrentThreadId();
  // create the tabs window
  m_pTabbarWnd = new CTabBarsWnd();
  m_pTabbarWnd->Create(CWnd::FromHandle(g_pSiFrameWnd->GetSafeHwnd()), 
        RBS_BANDBORDERS | RBS_AUTOSIZE | RBS_FIXEDORDER | RBS_DBLCLKTOGGLE, 
          WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CBRS_TOP | CBRS_SIZE_FIXED, AFX_IDW_REBAR );

m_pMainWnd = m_pTabbarWnd;//这很重要,否则这个线程就无法退出
    g_pSiFrameWnd->SetTabbarWnd(m_pTabbarWnd->GetSafeHwnd());
    g_MdiChildMng.SetTabbarWnd(m_pTabbarWnd->GetSafeHwnd());

m_pTabbarWnd->SetWindowPos(CWnd::FromHandle(hMDIWnd)->GetWindow(GW_HWNDPREV), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

g_pSiMDIClientWnd = new CSiMDIWnd();
    g_pSiMDIClientWnd->SetTabbarWnd(m_pTabbarWnd->GetSafeHwnd());
    DebugTracing(gnDbgLevelNormalDebug,_T("MDI Client Attach..."));
    g_pSiMDIClientWnd->Attach(hMDIWnd);
    DebugTracing(gnDbgLevelNormalDebug,_T("MDI Client Enum..."));
    g_pSiMDIClientWnd->EnumMdiChildWnd(g_MdiChildMng,TRUE);
    DebugTracing(gnDbgLevelNormalDebug,_T("MDI Client Enum end (%d)"),g_MdiChildMng.GetChildCount());
    pGlobalActiveSIWindow = g_MdiChildMng.LookupMdiChild(g_pSiMDIClientWnd->MDIGetActive(NULL));
    g_pSiMDIClientWnd->SetManaging(true);

return TRUE;
}

是不是很象标准单文档结构的MFC程序中的CxxxApp::InitInstance()函数?特别是对m_pMainWnd的赋值?对m_pMainWnd赋值其实很重要,否则线程就会直接退出,对m_pMainWnd赋值还有一个好处,就是关闭m_pTabbarWnd窗口就会中止CTabWndUIThread线程,这和标准单文档结构的MFC程序中的结果一样。

CTabWndUIThread::InitInstance()函数中有很多是对“Source Insight”内部窗口进行hook的代码,那么TabSiPlus是如何得到这些窗口的句柄呢,又是如何关联它们之间的消息呢,请看下篇:给Source Insight做个外挂系列之四--分析“Source Insight”

Source Insignt文件标签外挂:TabSiPlus的下载地址:
 http://blog.csdn.net/orbit/

给Source Insight做个外挂系列之三--构建外挂软件的定制代码框架的更多相关文章

  1. 给Source Insight做个外挂系列之一--发现Source Insight

    一提到外挂程序,大家肯定都不陌生,QQ就有很多个版本的去广告外挂,很多游戏也有用于扩展功能或者作弊的工具,其中很多也是以外挂的形式提供的.外挂和插件的区别在于插件通常依赖于程序的支持,如果程序不支持插 ...

  2. 给Source Insight做个外挂系列之六--“TabSiPlus”的其它问题

    关于如何做一个Source Insight外挂插件的全过程都已经写完了,这么一点东西拖了一年的时间才写完,足以说明我是一个很懒的人,如果不是很多朋友的关心和督促,恐怕是难以完成了.许多朋友希望顺着本文 ...

  3. 给Source Insight做个外挂系列之二--将本地代码注入到Source Insight进程

    上一篇文章介绍了如何发现正在运行的“Source Insight”窗口,本篇将介绍“TabSiPlus”是如何进行代码注入的.Windows 9x以后的Windows操作系统都对进程空间进行了严格的保 ...

  4. 给Source Insight做个外挂系列之五--Insight “TabSiPlus”

    “TabSiPlus 外挂插件”主要有两部分组成,分别是“外挂插件加载器”和“插件动态库”.“插件动态库”完成Source Insight窗口的Hook,显示Tab标签栏,截获Source Insig ...

  5. 给Source Insight做个外挂系列之四--分析“Source Insight”

    外挂的目的就是将代码注入到其它进程中,所以必须要有目标进程才能完成注入,而所谓的目标进程通常是某软件的一部分或者是全部,所以要对目标程序有深入地了解.一般外挂都是针对某个应用程序开发的,其装载.运行都 ...

  6. 【转】破解Source Insight 3.5.0072过程 附:安装软件+注册机

    转载地址:http://blog.csdn.net/qs_hud/article/details/8884867 注册机及软件下载地址:http://download.csdn.net/detail/ ...

  7. Source Insight 3.X 标签插件v1.0发布

    Source Insight可以说是一款程序员必备的开发/阅读源码工具,美中不足的是SI没有标签栏,多个源码之间切换很不方便,于是我就乘闲暇之余写了该作品sihook:标签插件;不过严格意义上来说si ...

  8. Source Insight 插件

    一提到外挂程序,大家肯定都不陌生,QQ就有很多个版本的去广告外挂,很多游戏也有用于扩展功能或者作弊的工具,其中很多也是以外挂的形式提供的.外挂和插件的区别在于插件通常依赖于程序的支持,如果程序不支持插 ...

  9. Source Insight 4.0安装使用教程

    一.说明 Source Insight是什么:Source Insight是一款代码编缉.浏览.分析工具. Source Insight与文本编缉器有什么区别:Notepad++等文本编缉器也可以编缉 ...

随机推荐

  1. java19

    1:异常(理解) (1)程序出现的不正常的情况. (2)异常的体系 Throwable |--Error 严重问题,我们不处理. |--Exception |--RuntimeException 运行 ...

  2. Python多进程(2)——mmap模块与mmap对象

    本文介绍Python mmap模块与mmap对象的用法. mmap 模块提供“内存映射的文件对象”,mmap 对象可以用在使用 plain string 的地方,mmap 对象和 plain stri ...

  3. Python~recursive function递归函数

    尾递归实现循环 def fact(n): if n==1: return 1 else : return n * fact(n-1) raw_input() 字符而非数字 unsupported op ...

  4. iOS 多线程

    一 多线程基础 1.进程:进程就是系统中正在运行的应用程序.每个进程是相互独立的且都运行在各自受保护的运行空间内. 比如同时打开迅雷.Xcode,系统就会分别启动2个进程. 2.线程:进程在执行任务是 ...

  5. (iOS逆向工程)class-dump 安装与使用

    class-dump,是可以把OC运行时的声明的信息导出来的工具.说白了,就是可以导出.h文件.用class-dump可以把未经加密的app的头文件导出来.废话不多说.class-dump的下载地址是 ...

  6. 使用原生ajax处理json字符串

    我们使用得还是wamp,如果不知道环境怎么搭建,请在我的日志里面找,此处不在累赘. 什么是json?JSON的全称是 Javascript Object Notation(javascript对象表示 ...

  7. Core Data使用

    注意:每次修改CoreData的Attribute时记得把应用给删除重装,要不会崩,因为建立的数据库文件还在该目录下,里面的字段没有更改,所以不能匹配就会崩溃,切忌,要不就每次进来把文件先删除,再建立 ...

  8. vagrant安装及使用方法

    http://www.chenjie.info/1757 http://blog.csdn.net/zsl10/article/category/6324870   --以下转自MaxWellDuva ...

  9. nmon的安装

    安装 mkdir /usr/local/nmon cd /usr/local/nmon wget http://sourceforge.net/projects/nmon/files/nmon_lin ...

  10. Jetty使用教程(四:24-27)—Jetty开发指南

    二十四.处理器(Handler ) 24.1 编写一个常用的Handler Jetty的Handler组件用来处理接收到的请求. 很多使用者不需要编写Jetty的Handler ,而是通过使用Serv ...