钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。总感觉这是windows留下来的应用程序的后门之类的吧。

  第一次接触这个,是刚来新公司,领导给了我一个任务,需要监听另外一个系统从串口获取的数据,之前也做过一些串口编程之类的。经过长时间的调研(google),才知道串口是独占的,虽然CreateFile 有参数是否独占,但是windows 规定串口只能独占,所以即使你设置共享模式,也没用。这就有问题了,人家CNS系统在占用串口,我怎么用。当时查询资料说是用钩子,但是查了好久,网上大都是不是勾键盘,就是勾MessageBox。机制如我,想到了既然可以勾MessageBox ,那就一定能勾住ReadFile,这两货都是windows API 。 所以当时就这么干了。

  网上有很多方法,有的需要更改导入表之类的,太高深了,幸好微软自己提供了专门的库叫Detours,这个东西就可以勾住任何的windows API ,大喜,经过测试之后,果然可以。不过又有了新问题,我需要注入到其他应用程序啊,怎么办,有个CreateRemoteThread这个函数可以做到,从字面意思看,就是创建一个远程线程,又喜,开始埋头找这个函数的用法之类的,当然中途也遇到了诸如提权 之类的新问题。不过Google是个好东西。不过这种方式呢需要将我们的程序封装成dll的形式,然后才能加载。

BOOL EnableDebugPrivilege();
DWORD GetTargetProcessID(const char *processExeName)
{
if(!EnableDebugPrivilege()){
printf("EnableDebugPrivilege faild\n");
}
if (processExeName == NULL) {
return ;
} HANDLE hSnapshot; hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, );
if (INVALID_HANDLE_VALUE == hSnapshot) {
printf("%d\n", GetLastError());
return ;
} PROCESSENTRY32 pe;
BOOL bRet = FALSE; pe.dwSize = sizeof (PROCESSENTRY32);
bRet = Process32First(hSnapshot, &pe);
while (bRet) {
_bstr_t b(pe.szExeFile);
const char* c = b;
if (strstr(processExeName, c)) {
return pe.th32ProcessID;
} else {
ZeroMemory(&pe, sizeof (PROCESSENTRY32));
pe.dwSize = sizeof (PROCESSENTRY32);
bRet = Process32Next(hSnapshot, &pe);
}
} return ;
}
BOOL EnableDebugPrivilege()
{
HANDLE hSnap;
HANDLE hkernel32 = NULL; //被注入进程的句柄
PROCESSENTRY32 pe;
BOOL bNext;
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID Luid;
LPVOID p;
FARPROC pfn;
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS_P,&hToken))
{
printf("Warning:提升权限失败\n");
system("pause");
return ;
} if (!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&Luid))
{
printf("Warning:提升权限失败\n");
system("pause");
return ;
} tp.PrivilegeCount = ;
tp.Privileges[].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[].Luid = Luid; if (!AdjustTokenPrivileges(hToken,,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL))
{
printf("Warning:提升权限失败\n");
system("pause");
return ;
}
return ;
}
BOOL InjectDll(const char *DllFullPath, const DWORD dwRemoteProcessId)
{
if (DllFullPath == NULL) {
return FALSE;
}
if (dwRemoteProcessId <= ) {
return FALSE;
}
HANDLE hRemoteProcess; hRemoteProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwRemoteProcessId);
if (NULL == hRemoteProcess) {
printf("Warning:OpenProcess:%d\n", GetLastError());
return FALSE;
} char *pRemoteAddr;
int len = strlen(DllFullPath) + ;
pRemoteAddr = (char *)VirtualAllocEx(hRemoteProcess, NULL, len, MEM_COMMIT, PAGE_READWRITE);
if (NULL == pRemoteAddr) {
printf("Warning:VirtualAllocEx:%d\n", GetLastError());
goto error;
} if (!WriteProcessMemory(hRemoteProcess, pRemoteAddr, DllFullPath, len, NULL)) {
printf("Warning:WriteProcessMemory:%d\n", GetLastError());
goto error;
} HMODULE hModule;
char LoadLibraryA[] = "LoadLibraryA"; hModule = GetModuleHandle("kernel32.dll"); FARPROC LoadLibraryAAddr;
LoadLibraryAAddr = GetProcAddress(hModule, LoadLibraryA);
if (NULL == LoadLibraryAAddr) {
printf("Warning:GetProcAddress:%d\n", GetLastError());
goto error;
} HANDLE remoteThread;
remoteThread = CreateRemoteThread(hRemoteProcess, NULL, , (LPTHREAD_START_ROUTINE)LoadLibraryAAddr, pRemoteAddr, , NULL);
if (NULL == remoteThread) {
printf("Warning:CreateRemoteThread:%d\n", GetLastError());
goto error;
} WaitForSingleObject(hRemoteProcess, INFINITE);
VirtualFreeEx(hRemoteProcess, pRemoteAddr, len, MEM_DECOMMIT); CloseHandle(hRemoteProcess);
CloseHandle(remoteThread);
return TRUE; error:
CloseHandle(hRemoteProcess);
return FALSE;
}

  这样我们就可以在远程应用程序中加载我们自己的动态库,加载动态库之后,我们当然需要建立我们自己的线程之类的,让我们的服务跑起来。这个时候,就可以用到微软的库了,不过微软的库也只限于32位应用程序,对于64位应用程序听说是收费的。9999美元呐!!!哈哈 不过这就够了,幸好客户是xp系统。

// InjectDll.cpp : Defines the exported functions for the DLL application.
// #include "stdafx.h"
#include "Detours.h"
#include <stdio.h>
#include <iostream> #pragma comment(lib,"Detours.lib") //修改MessageBoxW 的响应函数
static int (WINAPI * OLD_MessageBoxW)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType) = MessageBoxW;
int WINAPI NEW_MessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType)
{
// 修改输入参数,调用原函数
int ret = OLD_MessageBoxW(hWnd,L" 输入参数已修改 " ,L" [测试] " ,uType);
return ret;
} //修改MessageBoxA的响应函数
static int (WINAPI * OLD_MessageBoxA)( __in_opt HWND hWnd,
__in_opt LPCSTR lpText,
__in_opt LPCSTR lpCaption,
__in UINT uType) = MessageBoxA;
int WINAPI NEW_MessageBoxA(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType)
{
int ret = OLD_MessageBoxA(hWnd," 输入参数已修改 " ," [测试] " ,uType);
return ret;
} VOID Hook()
{
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread()); // 这里可以连续多次调用DetourAttach,表明HOOK多个函数
DetourAttach( & (PVOID & )OLD_MessageBoxA,NEW_MessageBoxA);
DetourAttach( & (PVOID & )OLD_MessageBoxW,NEW_MessageBoxW); DetourTransactionCommit();
} VOID UnHook()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread()); // 这里可以连续多次调用DetourDetach,表明撤销多个函数HOOK
DetourDetach( & (PVOID & )OLD_MessageBoxA,NEW_MessageBoxA);
DetourDetach( & (PVOID & )OLD_MessageBoxW,NEW_MessageBoxW); DetourTransactionCommit(); }

  之前勾ReadFile的程序没找见,不过都一样了。不过需要注意的一点就是,当接收到数据之后,需要立马吧数据保存起来,然后马上返回,不可做太多逻辑,因为会影响第三方应用程序。之后,就可以在我们自己的线程里处理这些数据了。为了达到我的目的,当我是在线程里创建里socket 服务器,当有客户端连接进来,就把数据传出去。虽然这样做也不是很好,但是时间也比较紧,就这样做了。考虑到性能问题,千万不能把原程序给人家崩溃了。这个程序跑了整整两天,监听串口数据,居然正常运行了两天。不过呢,任务也算完成了。哈哈哈。又掌握了一种新的软件运行方式。给自己点个赞!!

  最近64位的Detour 居然也被我找见了。win7 64位也测试成功!!!

 

windows 注入 之 CreateRemoteThread的更多相关文章

  1. 远程线程注入方法CreateRemoteThread

    最近在整理学习Windows注入方面的知识,这个远程注入前面早写过,现在看看人家博客的理解整理,整理, 需要源码的可以到我的github上下载. 链接是  https://github.com/Ars ...

  2. dll注入遇到CreateRemoteThread()返回错误代码5

    在进行dll注入的时候,发现触发了CreateRemoteThread()的错误并返回错误代码5,刚开始以为权限不够,用了管理员权限和加了SetPrivilege()函数提权和用NtCreateThr ...

  3. windows 注入 之 SetWindowHookEx

    前面的项目用到hook 还是在半年前,没想到最近有用到了,说实话,在项目组就提出,能用别的办法还是不要用这种,毕竟不太正道(感觉哈). 最近又牵扯到第三方对接的任务,没办法我又回到了HOOK上了.与窗 ...

  4. 【windows核心编程】远程线程DLL注入

    15.1 DLL注入 目前公开的DLL注入技巧共有以下几种: 1.注入表注入 2.ComRes注入 3.APC注入 4.消息钩子注入 5.远线程注入 6.依赖可信进程注入 7.劫持进程创建注入 8.输 ...

  5. 使用CreateRemoteThread把代码远程注入指定exe执行

    由于本人也是新手,如果有朋友不懂windows api相关知识,我相信查阅书籍或者百度会比我说有帮助的多,下面就我所做简单复述一下过程,欢迎指正缺点. 效果图示如下: 做的这个例子首先是创建了一个MF ...

  6. Dll注入:X86/X64 远程线程CreateRemoteThread 注入

    远线程注入原理是利用Windows 系统中CreateRemoteThread()这个API,其中第4个参数是准备运行的线程,我们可以将LoadLibrary()填入其中,这样就可以执行远程进程中的L ...

  7. Android 注入详解

    Android下的注入的效果是类似于Windows下的dll注入,关于Windows下面的注入可以参考这篇文章Windows注入术.而Android一般处理器是arm架构,内核是基于linux,因此进 ...

  8. C++注入记事本升级版,给记事本弄爱心

    #include <iostream>; using namespace std; #include <windows.h>; #include <tlhelp32.h& ...

  9. C++注入记事本

    #include <iostream>; using namespace std; #include <windows.h>; #include <tlhelp32.h& ...

随机推荐

  1. JAVA基础——异常详解

    JAVA异常与异常处理详解 一.异常简介 什么是异常? 异常就是有异于常态,和正常情况不一样,有错误出错.在java中,阻止当前方法或作用域的情况,称之为异常. java中异常的体系是怎么样的呢? 1 ...

  2. h5可预览 图片ajax上传 (补更),后台数据获取方法---php

    原理是 先获取,然后手动转移文件路径,不然会被服务器自动删除 demo如下: <?php header('content-Type:text/html;charset=utf-8'); $fil ...

  3. Chrome浏览器扩展开发系列之十五:跨域访问的XMLHttpRequest对象

    XMLHttpRequest对象是W3C的标准API,用于访问服务器资源.XMLHttpRequest对象支持多种文本格式,如XML和JSON等.XMLHttpRequest对象可以通过HTTP和HT ...

  4. JavaWeb 后端 <十四> 文件上传下载

    1.文件上传与下载 案例: 注册表单/保存商品等相关模块! --à 注册选择头像 / 商品图片 (数据库:存储图片路径 / 图片保存到服务器中指定的目录) 1.1 文件上传 文件上传,要点: 前台: ...

  5. 8位基本定时器(TIM4)

    简介:该定时器由一个带可编程预分频器的8位自动重载的向上计数器所组成,它可以用来作为时基发生器,具有溢出中断功能. 主要功能: (1)8位向上计数的自动重载计数器: (2)3位可编程的预分配器(可在运 ...

  6. Go语言string,int,int64 ,float转换

    (1)int转string s := strconv.Itoa(i)等价于s := strconv.FormatInt(int64(i), 10) (2)int64转string i := int64 ...

  7. UDP和多线程服务器

    UDP: UDP是数据报文传输协议,这个传输协议比较野蛮,发送端不需要理会接收端是否存在,直接就发送数据,不会像TCP协议一样建立连接.如果接收端不存在的话,发送的数据就会丢失,UDP协议不会去理会数 ...

  8. 小白也能看懂的插件化DroidPlugin原理(二)-- 反射机制和Hook入门

    前言:在上一篇博文<小白也能看懂的插件化DroidPlugin原理(一)-- 动态代理>中详细介绍了 DroidPlugin 原理中涉及到的动态代理模式,看完上篇博文后你就会发现原来动态代 ...

  9. [luogu P3797] 妖梦斩木棒 [线段树]

    题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看做由三种小段构成,中间的 ...

  10. sqlserver提高篇

    Microsoft SQL Server2008复习提高 一.Microsoft SQL Server 系统的体系结构 1.Microsoft SQL Server2008由4个主要的部分组成,即4个 ...