1.C++ DLL注入微信hook实现自动接收消息
2.JS逆向快速定位关键点之9大通用hook脚本
3.HOOK的断点断点原理分析与easy_hook逆向题分析
4.webpack5loader和plugin原理解析
5.Python微信机器人第六七篇: 封装32位和64位Python hook框架实战打印微信日志
C++ DLL注入微信hook实现自动接收消息
在接收消息的探讨中,重点在于追踪独一无二的源码消息内容,而不是断点断点发送者。发送者可能会引发混淆,源码尤其是断点断点面对大量历史消息或存于数据库中的记录。因此,源码手游媒体源码我们的断点断点焦点转向了消息内容。
为了获取最新消息,源码我们采取了简单但有效的断点断点策略:借助第三方工具如文件传输助手,向特定好友发送一条消息。源码确保不开启与该好友的断点断点聊天窗口,以避免消息提示音和未读角标,源码方便定位新消息。断点断点
进行消息发送后,源码使用CE扫描工具筛选信息。断点断点多次过滤后,剩余的地址通常指向关键数据。随机选择一个地址,通过OD工具进行内存断点设置,拦截消息接收的函数。通过观察内存写入操作,我们能够识别出接收消息的特定调用点。
在数据窗口下设置内存写入断点,发送新消息并断点处理。堆栈窗口显示了消息内容、发送者、头像网址等详细信息。继续探索,直至找到消息接收的同步标识和相关的函数调用。成功定位后,就可以进行钩子操作,以拦截和处理消息。
找到合适的钩子函数后,通过调整代码实现消息拦截与处理。快云主机源码利用jmp指令的特性,确定跳转代码的计算公式,进而实现与目标函数的连接。编写hook函数和执行代码,确保安全且高效地处理消息。
最后,实现消息处理逻辑,包括备份寄存器、执行自定义代码、恢复寄存器以及调用原函数以避免程序崩溃。确保消息接收流程连续无阻,同时让Python监听消息,实现自动化接收。
通过上述步骤,我们成功地实现了自动接收微信消息的钩子功能,为自动化应用提供了有力支持。这一过程既涉及技巧也需细心操作,确保在不干扰正常通讯的前提下实现自动化目标。
JS逆向快速定位关键点之9大通用hook脚本
在JavaScript逆向工程中,快速定位关键点是至关重要的。这里有九种通用的hook脚本策略,帮助我们深入分析代码行为: 首先,Cookie Hook帮助我们定位Cookie中与关键字"v"相关的参数生成位置,一旦匹配,就会自动设置断点。 对于HTTP头部参数,header参数Hook可以用于跟踪请求中特定字段的变化。 通过简单地在代码中插入debugger,Hook过debugger方法为我们提供了一个直观的检查点,便于调试。 URL Hook专注于URL中的关键参数,当遇到包含"login"的请求时,会自动设立断点,主页的使用源码便于追踪网络请求。 在处理加密的站点时,hook JSON.stringify和 JSON.parse可以让我们洞察数据在字符串和对象间的转换过程。 JavaScript的eval 功能,通过提前设置的hook,hook eval可以记录下所有动态执行的JS代码,便于分析。 同样,hook Function会捕获所有函数的执行,让我们看到将要运行的JS源码。最后,别忘了防范反调试,确保在执行过程中不会被检测到,这是逆向工程中必不可少的通用反调试技巧。
这些脚本工具为深入JavaScript代码提供了强大的支持,帮助我们轻松定位关键逻辑点。
HOOK的原理分析与easy_hook逆向题分析
HOOK是一种强大的技术,它允许在执行目标函数之前插入代码,以获取程序执行流程的控制权。它常用于二次开发、安全防护以及系统调用监控。在Windows系统中,API HOOK通过修改API调用的入口地址,实现对程序的拦截和修改。实现过程包括获取目标程序中API的入口地址、保存原始地址、修改入口地址指向HOOK函数,以及在HOOK函数内实现自定义功能。使用API HOOK时需注意安全性和稳定性。
以MessageBoxA函数为例,通过下软件断点分析其汇编代码流程。断点下在函数开始处,执行汇编指令以分配堆栈空间和保存现场。星象时间窗口源码参数通过push指令压入堆栈,然后调用用户函数显示弹窗。HOOK后,修改了汇编指令,跳转到自定义HOOK函数。该函数内修改参数后,调用原始函数执行弹窗显示。
在攻防世界逆向题“Easy Hook”分析中,首先确定程序是位PE文件。使用IDA进行静态分析,获取main函数的反汇编代码,分析伪代码并确定hook函数和目标函数。运行程序并分析hook过程,发现程序通过hook写入文件操作的函数来加密输入。通过深入分析hook函数、加密过程和返回值,解密flag得到答案。整个过程涉及HOOK技术、静态分析以及逆向工程。
webpack5loader和plugin原理解析
大家好,今天为大家解析下loader和plugin一、区别loader是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中
plugin赋予了Webpack各种灵活的功能,例如打包优化、资源管理、环境变量注入等,目的是解决loader无法实现的其他事从整个运行时机上来看,如下图所示:
可以看到,两者在运行时机上的qt经典项目源码区别:
loader运行在打包文件之前plugins在整个编译周期都起作用在Webpack运行的生命周期中会广播出许多事件,Plugin可以监听这些事件,在合适的时机通过Webpack提供的API改变输出结果
对于loader,实质是一个转换器,将A文件进行编译形成B文件,操作的是文件,比如将A.scss或A.less转变为B.css,单纯的文件转换过程
下面我们来看看loader和plugin实现的原理
Loader原理loader概念帮助webpack将不同类型的文件转换为webpack可识别的模块。
loader执行顺序分类
pre:前置loader
normal:普通loader
inline:内联loader
post:后置loader
执行顺序
4类loader的执行优级为:pre>normal>inline>post。
相同优先级的loader执行顺序为:从右到左,从下到上。
例如:
//此时loader执行顺序:loader3-loader2-loader1module:{ rules:[{ test:/\.js$/,loader:"loader1",},{ test:/\.js$/,loader:"loader2",},{ test:/\.js$/,loader:"loader3",},],},//此时loader执行顺序:loader1-loader2-loader3module:{ rules:[{ enforce:"pre",test:/\.js$/,loader:"loader1",},{ //没有enforce就是normaltest:/\.js$/,loader:"loader2",},{ enforce:"post",test:/\.js$/,loader:"loader3",},],},使用loader的方式
配置方式:在webpack.config.js文件中指定loader。(pre、normal、postloader)
内联方式:在每个import语句中显式指定loader。(inlineloader)
开发一个loader1.最简单的loader//loaders/loader1.jsmodule.exports=functionloader1(content){ console.log("hellofirstloader");returncontent;};它接受要处理的源码作为参数,输出转换后的js代码。
2.loader接受的参数content源文件的内容
mapSourceMap数据
meta数据,可以是任何内容
loader分类1.同步loadermodule.exports=function(content,map,meta){ returncontent;};this.callback方法则更灵活,因为它允许传递多个参数,而不仅仅是content。
module.exports=function(content,map,meta){ //传递map,让source-map不中断//传递meta,让下一个loader接收到其他参数this.callback(null,content,map,meta);return;//当调用callback()函数时,总是返回undefined};2.异步loadermodule.exports=function(content,map,meta){ constcallback=this.async();//进行异步操作setTimeout(()=>{ callback(null,result,map,meta);},);};由于同步计算过于耗时,在Node.js这样的单线程环境下进行此操作并不是好的方案,我们建议尽可能地使你的loader异步化。但如果计算量很小,同步loader也是可以的。
3.RawLoader默认情况下,资源文件会被转化为UTF-8字符串,然后传给loader。通过设置raw为true,loader可以接收原始的Buffer。
module.exports=function(content){ //content是一个Buffer数据returncontent;};module.exports.raw=true;//开启RawLoader4.PitchingLoadermodule.exports=function(content){ returncontent;};module.exports.pitch=function(remainingRequest,precedingRequest,data){ console.log("dosomethings");};webpack会先从左到右执行loader链中的每个loader上的pitch方法(如果有),然后再从右到左执行loader链中的每个loader上的普通loader方法。
在这个过程中如果任何pitch有返回值,则loader链被阻断。webpack会跳过后面所有的的pitch和loader,直接进入上一个loader。
loaderAPI方法名含义用法this.async异步回调loader。返回this.callbackconstcallback=this.async()this.callback可以同步或者异步调用的并返回多个结果的函数this.callback(err,content,sourceMap?,meta?)this.getOptions(schema)获取loader的optionsthis.getOptions(schema)this.emitFile产生一个文件this.emitFile(name,content,sourceMap)this.utils.contextify返回一个相对路径this.utils.contextify(context,request)this.utils.absolutify返回一个绝对路径this.utils.absolutify(context,request)更多文档,请查阅webpack官方loaderapi文档
手写clean-log-loader作用:用来清理js代码中的console.log
//loaders/clean-log-loader.jsmodule.exports=functioncleanLogLoader(content){ //将console.log替换为空returncontent.replace(/console\.log\(.*\);?/g,"");};手写banner-loader作用:给js代码添加文本注释
loaders/banner-loader/index.js
constschema=require("./schema.json");module.exports=function(content){ //获取loader的options,同时对options内容进行校验//schema是options的校验规则(符合JSONschema规则)constoptions=this.getOptions(schema);constprefix=`/**Author:${ options.author}*/`;return`${ prefix}\n${ content}`;};loaders/banner-loader/schema.json
//此时loader执行顺序:loader1-loader2-loader3module:{ rules:[{ enforce:"pre",test:/\.js$/,loader:"loader1",},{ //没有enforce就是normaltest:/\.js$/,loader:"loader2",},{ enforce:"post",test:/\.js$/,loader:"loader3",},],},0手写babel-loader作用:编译js代码,将ES6+语法编译成ES5-语法。
下载依赖
//此时loader执行顺序:loader1-loader2-loader3module:{ rules:[{ enforce:"pre",test:/\.js$/,loader:"loader1",},{ //没有enforce就是normaltest:/\.js$/,loader:"loader2",},{ enforce:"post",test:/\.js$/,loader:"loader3",},],},1loaders/babel-loader/index.js
//此时loader执行顺序:loader1-loader2-loader3module:{ rules:[{ enforce:"pre",test:/\.js$/,loader:"loader1",},{ //没有enforce就是normaltest:/\.js$/,loader:"loader2",},{ enforce:"post",test:/\.js$/,loader:"loader3",},],},2loaders/banner-loader/schema.json
//此时loader执行顺序:loader1-loader2-loader3module:{ rules:[{ enforce:"pre",test:/\.js$/,loader:"loader1",},{ //没有enforce就是normaltest:/\.js$/,loader:"loader2",},{ enforce:"post",test:/\.js$/,loader:"loader3",},],},3手写file-loader作用:将文件原封不动输出出去
下载包
//此时loader执行顺序:loader1-loader2-loader3module:{ rules:[{ enforce:"pre",test:/\.js$/,loader:"loader1",},{ //没有enforce就是normaltest:/\.js$/,loader:"loader2",},{ enforce:"post",test:/\.js$/,loader:"loader3",},],},4loaders/file-loader.js
//此时loader执行顺序:loader1-loader2-loader3module:{ rules:[{ enforce:"pre",test:/\.js$/,loader:"loader1",},{ //没有enforce就是normaltest:/\.js$/,loader:"loader2",},{ enforce:"post",test:/\.js$/,loader:"loader3",},],},5loader配置
//此时loader执行顺序:loader1-loader2-loader3module:{ rules:[{ enforce:"pre",test:/\.js$/,loader:"loader1",},{ //没有enforce就是normaltest:/\.js$/,loader:"loader2",},{ enforce:"post",test:/\.js$/,loader:"loader3",},],},6手写style-loader作用:动态创建style标签,插入js中的样式代码,使样式生效。
loaders/style-loader.js
//此时loader执行顺序:loader1-loader2-loader3module:{ rules:[{ enforce:"pre",test:/\.js$/,loader:"loader1",},{ //没有enforce就是normaltest:/\.js$/,loader:"loader2",},{ enforce:"post",test:/\.js$/,loader:"loader3",},],},7Plugin原理Plugin的作用通过插件我们可以扩展webpack,加入自定义的构建行为,使webpack可以执行更广泛的任务,拥有更强的构建能力。
Plugin工作原理webpack就像一条生产线,要经过一系列处理流程后才能将源文件转换成输出结果。这条生产线上的每个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理。插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。webpack通过Tapable来组织这条复杂的生产线。webpack在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条生产线中,去改变生产线的运作。webpack的事件流机制保证了插件的有序性,使得整个系统扩展性很好。——「深入浅出Webpack」
站在代码逻辑的角度就是:webpack在编译代码过程中,会触发一系列Tapable钩子事件,插件所做的,就是找到相应的钩子,往上面挂上自己的任务,也就是注册事件,这样,当webpack构建的时候,插件注册的事件就会随着钩子的触发而执行了。
Webpack内部的钩子什么是钩子钩子的本质就是:事件。为了方便我们直接介入和控制编译过程,webpack把编译过程中触发的各类关键事件封装成事件接口暴露了出来。这些接口被很形象地称做:hooks(钩子)。开发插件,离不开这些钩子。
TapableTapable为webpack提供了统一的插件接口(钩子)类型定义,它是webpack的核心功能库。webpack中目前有十种hooks,在Tapable源码中可以看到,他们是:
//此时loader执行顺序:loader1-loader2-loader3module:{ rules:[{ enforce:"pre",test:/\.js$/,loader:"loader1",},{ //没有enforce就是normaltest:/\.js$/,loader:"loader2",},{ enforce:"post",test:/\.js$/,loader:"loader3",},],},8Tapable还统一暴露了三个方法给插件,用于注入不同类型的自定义构建行为:
tap:可以注册同步钩子和异步钩子。
tapAsync:回调方式注册异步钩子。
tapPromise:Promise方式注册异步钩子。
Plugin构建对象Compilercompiler对象中保存着完整的Webpack环境配置,每次启动webpack构建时它都是一个独一无二,仅仅会创建一次的对象。
这个对象会在首次启动Webpack时创建,我们可以通过compiler对象上访问到Webapck的主环境配置,比如loader、plugin等等配置信息。
它有以下主要属性:
compiler.options可以访问本次启动webpack时候所有的配置文件,包括但不限于loaders、entry、output、plugin等等完整配置信息。
compiler.inputFileSystem和compiler.outputFileSystem可以进行文件操作,相当于Nodejs中fs。
compiler.hooks可以注册tapable的不同种类Hook,从而可以在compiler生命周期中植入不同的逻辑。
compilerhooks文档
Compilationcompilation对象代表一次资源的构建,compilation实例能够访问所有的模块和它们的依赖。
一个compilation对象会对构建依赖图中所有模块,进行编译。在编译阶段,模块会被加载(load)、封存(seal)、优化(optimize)、分块(chunk)、哈希(hash)和重新创建(restore)。
它有以下主要属性:
compilation.modules可以访问所有模块,打包的每一个文件都是一个模块。
compilation.chunkschunk即是多个modules组成而来的一个代码块。入口文件引入的资源组成一个chunk,通过代码分割的模块又是另外的chunk。
compilation.assets可以访问本次打包生成所有文件的结果。
compilation.hooks可以注册tapable的不同种类Hook,用于在compilation编译模块阶段进行逻辑添加以及修改。
compilationhooks文档
生命周期简图开发一个插件最简单的插件plugins/test-plugin.js
//此时loader执行顺序:loader1-loader2-loader3module:{ rules:[{ enforce:"pre",test:/\.js$/,loader:"loader1",},{ //没有enforce就是normaltest:/\.js$/,loader:"loader2",},{ enforce:"post",test:/\.js$/,loader:"loader3",},],},9注册hook//loaders/loader1.jsmodule.exports=functionloader1(content){ console.log("hellofirstloader");returncontent;};0启动调试通过调试查看compiler和compilation对象数据情况。
package.json配置指令
//loaders/loader1.jsmodule.exports=functionloader1(content){ console.log("hellofirstloader");returncontent;};1运行指令
//loaders/loader1.jsmodule.exports=functionloader1(content){ console.log("hellofirstloader");returncontent;};2此时控制台输出以下内容:
PSC:\Users\\Desktop\source>//loaders/loader1.jsmodule.exports=functionloader1(content){ console.log("hellofirstloader");returncontent;};2>source@1.0.0debug>node--inspect-brk./node_modules/webpack-cli/bin/cli.jsDebuggerlisteningonws://.0.0.1:/ea-7b--a7-fccForhelp,see:/post/开发思路:
我们需要借助html-webpack-plugin来实现
在html-webpack-plugin输出index.html前将内联runtime注入进去
删除多余的runtime文件
如何操作html-webpack-plugin?官方文档
实现:
//loaders/loader1.jsmodule.exports=functionloader1(content){ console.log("hellofirstloader");returncontent;};7Python微信机器人第六七篇: 封装位和位Python hook框架实战打印微信日志
目录修整
目前的系列目录(后面会根据实际情况变动):
上上篇文章说的以后只更新位版本这句话收回,以后会同时更新位和位的最新版本,已经可以在Python中使用Detours来hook 位版本。
为了加快进度,第六篇和第七篇同一天发布,这篇文章为使用总结,想知道hook原理的可以看同时间发布的其他几篇文章。
温馨提示:本次发布的这几篇文章都是偏技术,想获取成品直接使用的可以等下一篇文章(实战位和位接收消息和消息防撤回)
另外,这篇文章开始建群,请关注github或者公众号菜单栏
封装好的Hook库位程序的Hook
hook的参数有两个:内存地址和回调函数。回调函数的参数是一个包含x所有寄存器的结构体指针,没有返回值。结构体的定义如下:
一个简单的Hook 示例:
context这个结构体获取的就是当执行到这个地址时的寄存器的值,这个和你用xdbg看到的寄存器的值是一样的。值的类型都定义成DWORD,如果寄存器是类型是其他类型,比如字符串或结构体,你需要在Python里做相应的转换,可以参考下面Hook日志的代码
你同样可以在回调函数里修改这个指针中寄存器的值,它会反映到实际的寄存器,案例的话会在消息防撤回那一篇文章演示。
位的Hook
因为位hook是封装的Detour,比位需要多定义一个函数指针,而且只能hook函数。所以hook之前需要知道被Hook的函数参数有几个,类型如果不知道的话,可以像上面一样都定义成c_uint。
回调函数的参数跟被Hook函数的参数必须一样,如果参数很多,你也可以用*arg来表示,示例代码如下:
另外,回调函数的返回值类型也需要和被Hook函数一样,一般都是先调用原函数获取返回值然后返回。如果返回错误类型的返回值,进程会崩溃。
案例
为什么要选择Hook日志做案例?日志是多线程打印的,如果Hook日志没有问题的话,其他任何位置的Hook基本都不会有问题。
效果
hook后的效果如下:
位代码
先定义回调函数,因为我需要同时获取参数和返回值,所以要hook两个地方(函数头和函数尾)。
用xdbg在日志函数头位置下个断点,看起来有两个有用的信息:EDX的代码路径和esp的函数返回地址。
定义回调函数:
然后看返回值,返回值获取的是EAX的值
在new一个Hook类hook这两个位置:
因为需要支持热加载,所以在hook之前先调用一下unhook,这样你修改代码就会生效新的hook。
使用
你想hook日志的话,先将github的代码拉下来,然后安装依赖,再运行main.py注入Python之后,修改robot.py, 添加如下代码控制台就会打印日志了:
github的代码更新了3.9.8.和3.9.8.两个版本,如果有更新的版本,请提issue。
位代码
xdbg打上断点,可以看到RDX是代码路径,而RDX是函数的第二个参数。因为获取不到寄存器,所以返回地址就拿不到了。
返回值如下, 也是char数组:
定义回调函数,日志函数有个参数,我就用args来代替了:
开始hook
代码更新
以后微信相关的代码统一到下面的仓库更新:
位和位hook的代码封装成库并发布到pypi,可以通过pip install py_process_hooker安装或者pip install --upgrade py_process_hooker更新,具体操作请看仓库说明。
其实微信相关的代码也可以发布到pypi,后面代码稳定下来再看要不要发布。因为目前需要频繁更新,比较麻烦。