一种动态地址的查询
背景
当我们注入一个进程,通过函数地址进行call时经常会遇到这样的一个问题。对方程序每周四会自动更新。更新后之前的函数地址就变化了,然后需要重新找地址。所以,我就使用了一个动态查询的方式。
第一步:先为需要call的函数生成特征码。特征码其实就是反汇编后,去掉地址,只留操作符。
function make_search(v: dword; ms: TMemoryStream; maxsize: integer): string;
var
offset: dword;
isnot_ret: boolean;
description: string;
begin
ms.Clear;
Result := '';
offset := v;
isnot_ret := true;
while isnot_ret do
begin
isnot_ret := pbyte(offset)^ <> $C3;
disassemble_find(offset, description, ms);
if Result <> '' then
Result := Result + #13#10;
Result := Result + description;
if ms.Size > 1024 then
Break;
end;
end;
disassemble_find 函数的行数太多了。
function disassemble_find(var offset: dword; var description: string; ms_find: TMemoryStream): string; overload;
var
memory: TMemory;
actualread: dword;
startoffset: dword;
tempresult: string;
tempst: string;
wordptr: ^word;
dwordptr: ^dword;
dwordptr2: ^dword;
singleptr: ^single;
doubleptr: ^double;
extenedptr: ^extended;
int64ptr: ^int64;
i, j: integer;
prefix: TPrefix;
prefix2: TPrefix;
isprefix: boolean;
last: dword;
foundit: boolean;
search_size: integer;
str_tmp: string;
begin
search_size := 0;
result := inttohex(offset, 8) + ' - ';
isprefix := true;
prefix := [$F0, $F2, $F3, $2E, $36, $3E, $26, $64, $65, $66, $67];
prefix2 := [];
//forced 16-bit
if mode16 then
prefix2 := prefix2 + [$66];
startoffset := offset;
readmemory(pointer(offset), addr(memory), 24, actualread);
/
if actualread > 0 then
begin
//I HATE THESE... (I propably will not add them all, but I'll see how far I get)
while isprefix do
begin
inc(offset);
if memory[0] in prefix then
begin
result := result + inttohexs(memory[0], 2) + ' ';
isprefix := true;
inc(startoffset);
prefix2 := prefix2 + [memory[0]];
ReadMemory(pointer(offset), addr(memory), 24, actualread);
end
else
isprefix := false;
end;
if $F0 in prefix2 then tempresult := 'lock ';
if $F2 in prefix2 then tempresult := tempresult + 'repne ';
if $F3 in prefix2 then tempresult := tempresult + 'repe ';
case memory[0] of //opcode
$00:
begin
description := 'Add';
tempresult := tempresult + 'add ' + MODRM(memory, prefix2, 1, 2, last) + r8(memory[1]);
inc(offset, last - 1);
end;
$01:
begin
description := 'Add';
if $66 in prefix2 then
tempresult := tempresult + 'ADD ' + MODRM(memory, prefix2, 1, 1, last) + r16(memory[1])
else
tempresult := tempresult + 'ADD ' + MODRM(memory, prefix2, 1, 0, last) + r32(memory[1]);
inc(offset, last - 1);
end;
$02:
begin
description := 'Add';
tempresult := tempresult + 'ADD ' + r8(memory[1]) + ',' + MODRM(memory, prefix2, 1, 2, last);
tempresult := copy(tempresult, 0, length(tempresult) - 1);
inc(offset, last - 1);
end;
$03:
begin
description := 'Add';
if $66 in prefix2 then
tempresult := tempresult + 'ADD ' + r16(memory[1]) + ',' + MODRM(memory, prefix2, 1, 1, last)
else
tempresult := tempresult + 'ADD ' + r32(memory[1]) + ',' + MODRM(memory, prefix2, 1, 0, last);
tempresult := copy(tempresult, 0, length(tempresult) - 1);
inc(offset, last - 1);
end;
$04:
begin
description := 'Add x to y';
tempresult := tempresult + 'ADD AL,' + inttohexs(memory[1], 2);
inc(offset);
end;
$05:
begin
description := 'Add x to y';
wordptr := @memory[1];
dwordptr := @memory[1];
if $66 in prefix2 then
begin
tempresult := tempresult + 'ADD AX,' + inttohexs(wordptr^, 4);
inc(offset, 2);
end
else
begin
tempresult := tempresult + 'ADD EAX,' + inttohexs(dwordptr^, 8);
inc(offset, 4);
end;
end;
第二步:查询函数地址
function search_address(ms_search: TMemoryStream; sl: tstringlist): string;
var
idx, i: integer;
ms: TMemoryStream;
Mem: TMemoryBasicInformation;
dwProtect, temp: cardinal;
msize: dword;
canread, willVirtualProtect: boolean;
procedure dosearch;
var
count, idx, i, l: integer;
s: string;
ms_old: TMemoryStream;
ms: TMemoryStream;
begin
ms_search.Position := 0;
ms_search.Read(count, sizeof(ms_search));
for i := 1 to count do
begin
ms := TMemoryStream.Create;
ms_old := TMemoryStream.Create;
ms_search.Read(l, sizeof(l));
setlength(s, l);
ms_search.Read(s[1], l);
ms_search.Read(l, sizeof(l));
ms_old.CopyFrom(ms_search, l);
ms_search.Read(l, sizeof(l));
ms.CopyFrom(ms_search, l);
//if SameText('Py_GetVersion', s) then
begin
idx := search_ms(integer(Mem.BaseAddress), Mem.RegionSize, ms_old);
if idx < 0 then
begin
idx := search_ms(integer(Mem.BaseAddress), Mem.RegionSize, ms);
end;
if idx >= 0 then
begin
sl.AddObject(s, pointer(idx));
if Result <> '' then
Result := Result + #13#10;
Result := Result + s + '=' + IntToStr(idx - integer(Mem.BaseAddress));
end;
end;
FreeAndNil(ms);
FreeAndNil(ms_old);
end;
end;
begin
Result := '';
idx := -1;
if length(Mems) <= 0 then
u_mem.test;
for i := 0 to high(Mems) do
begin
if SameText('mhmain.dll', GetItemFilePath(Mems[i], Modules)) then
if Mems[i].RegionSize > 1024 * 1024 * 4 then
begin
Mem := Mems[i];
idx := i;
Break;
end;
end;
if idx < 0 then
exit;
canread := not IsBadReadPtr(mem.BaseAddress, mem.RegionSize);
if not canread then
begin
if VirtualProtect(mem.BaseAddress, mem.RegionSize, PAGE_EXECUTE_READWRITE, @dwProtect) then
begin
canread := true;
willVirtualProtect := true;
end;
end;
if canread then
begin
dosearch;
end;
if willVirtualProtect then
VirtualProtect(mem.BaseAddress, mem.RegionSize, dwProtect, @temp);
end;
注意
同一个函数可能查到多个地址,但是可以根据多个地址进行校验。命中的范围最集中的那个范围中的地址,一般都是正确的地址。
相关文章:
一种动态地址的查询
背景 当我们注入一个进程,通过函数地址进行call时经常会遇到这样的一个问题。对方程序每周四会自动更新。更新后之前的函数地址就变化了,然后需要重新找地址。所以,我就使用了一个动态查询的方式。 第一步:先为需要call的函数生…...

周雨彤:用角色与生活,诠释审美的艺术
提到内娱审美优秀且持续在线的女演员,周雨彤绝对是其中最有代表性的一个。 独树一帜的表演美学 作为新生代演员中的实力派代表,周雨彤凭借细腻的表演和对角色的深度共情,在荧幕上留下了多个令人难忘的“出圈”形象。在《我在他乡挺好的》中…...

使用jks给空apk包签名
1、在平台官方下载空的apk包(上传应用时有提醒下载) 2、找到jdk目录,比如C:\Program Files\Java\jdk1.8\bin,并把下载的空包apk和jks文件放到bin下 3、以管理员身份运行cmd,如果不是管理员会签名失败 4、用cd定位到…...

500. 键盘行 771. 宝石与石头 简单 find接口的使用
500. 键盘行1 给你一个字符串数组 words ,只返回可以使用在 美式键盘 同一行的字母打印出来的单词。键盘如下图所示。 请注意,字符串 不区分大小写,相同字母的大小写形式都被视为在同一行。 美式键盘 中: 第一行由字符 "qwer…...

仙剑世界手游新手攻略 仙剑世界能用云手机玩吗
欢迎来到《仙剑世界》手游的仙侠世界!作为新手玩家,以下是一些详细的攻略和建议,帮助你快速上手并享受游戏的乐趣。 一、新手职业推荐 1.轩辕:这是一个偏辅助的职业,可以给队友提供输出加成等增益效果,不过…...
[题解]2024CCPC重庆站-小 C 的神秘图形
Sources:K - 小 C 的神秘图形Abstract:给定正整数 n ( 1 ≤ n ≤ 1 0 5 ) n(1\le n\le 10^5) n(1≤n≤105),三进制字符串 n 1 , n 2 ( ∣ n 1 ∣ ∣ n 2 ∣ n ) n_1,n_2(|n_1||n_2|n) n1,n2(∣n1∣∣n2∣n),按如下方法…...

NPS内网穿透SSH使用手册
1、说明 nps-一款轻量级、高性能、功能强大的内网穿透代理服务器 github地址:https://github.com/ehang-io/nps 官网文档地址:https://ehang-io.github.io/nps/#/?idnps 2、服务端 下载地址:https://github.com/ehang-io/nps/releases 下…...

大幂计算和大阶乘计算【C语言】
大幂计算: #include<stdio.h> long long int c[1000000]{0}; int main() {long long a,b,x1;c[0]1;printf("请输入底数:");scanf("%lld",&a);printf("请输入指数:");scanf("%lld",&b…...

【Linux】详谈 进程控制
目录 一、进程是什么 二、task_struct 三、查看进程 四、创建进程 4.1 fork函数的认识 4.2 2. fork函数的返回值 五、进程终止 5.1. 进程退出的场景 5.2. 进程常见的退出方法 5.2.1 从main返回 5.2.1.1 错误码 5.2.2 exit函数 5.2.3 _exit函数 5.2.4 缓冲区问题补…...
Linux top 命令
作用 top 是一个实时系统监控工具,用于查看系统的资源使用情况和进程状态。 示例 以下是一些常用的 top 命令示例: top :动态显示结果,每 3 秒刷新一次。 top -d 2:动态显示结果,每 2 秒刷新一次。 top …...

Leetcode 424-替换后的最长重复字符
给你一个字符串 s 和一个整数 k 。你可以选择字符串中的任一字符,并将其更改为任何其他大写英文字符。该操作最多可执行 k 次。 在执行上述操作后,返回 包含相同字母的最长子字符串的长度。 题解 可以先做LCR 167/Leetcode 03再做本题 滑动窗口&…...

《StyleDiffusion:通过扩散模型实现可控的解耦风格迁移》学习笔记
paper:2308.07863 目录 摘要 1、介绍 2、相关工作 2.1 神经风格迁移(NST) 2.2 解耦表示学习(DRL) 2.3 扩散模型(Diffusion Models) 3、方法 3.1 风格移除模块 3.2 风格转移模块 3.3 …...

Django 创建表时 “__str__ ”方法的使用
在 Django 模型中,__str__ 方法是一个 Python 特殊方法(也称为“魔术方法”),用于定义对象的字符串表示形式。它的作用是控制当对象被转换为字符串时,应该返回什么样的内容。 示例: 我在初学ModelForm时尝…...
图像处理之CSC
CSC 是 Color Space Conversion(色彩空间转换)的缩写,它涉及图像处理中的亮度、饱和度、对比度和色度等参数的调整。这些参数是图像处理中的核心概念,通常用于描述和操作图像的颜色信息。 以下是亮度、饱和度、对比度和色度与 CS…...
C语言数组之二维数组
C语言 主要内容 数组 二维数组 数组 二维数组 定义 二维数组本质上是一个行列式的组合,也就是说二维数组由行和列两部分组成,属于多维数组。二维数组数据是通过行列进行解读。二维数组可被视为一个特殊的一维数组,相当于二维数组又是一…...

PyTorch 源码学习:阅读经验 代码结构
分享自己在学习 PyTorch 源码时阅读过的资料。本文重点关注阅读 PyTorch 源码的经验和 PyTorch 的代码结构。因为 PyTorch 不同版本的源码实现有所不同,所以笔者在整理资料时尽可能按版本号升序,版本号见标题前[]。最新版本的源码实现还请查看 PyTorch 仓…...
vite+vue3开发低版本浏览器不支持es6语法的问题排坑笔记
重要提示:请首先完整阅读完文章内容后再操作,以免不必要的时间浪费!切记!!!在使用vitevue3开发unapp项目时,发现低版本浏览器不兼容es6的语法,如“?.” “??” 等,为了…...
C语言中printf()函数,格式输出符
在 C 语言中,printf() 函数的格式输出符(格式说明符)用于控制输出的格式和数据类型。以下是常见的格式说明符及其用法: 基本格式符 打印各种类型的值 格式输出符数据类型说明%dint输出有符号十进制整数%uunsigned int输出无符号…...

AI 编程工具—Cursor 进阶篇 数据分析
AI 编程工具—Cursor 进阶篇 数据分析 上一节课我们使用Cursor 生成了北京房产的销售数据,这一节我们使用Cursor对这些数据进行分析,也是我们尝试使用Cursor 去帮我们做数据分析,从而进一步发挥Cursor的能力,来帮助我们完成更多的事情 案例一 房产销售数据分析 @北京202…...
青少年编程与数学 02-009 Django 5 Web 编程 20课题、测试
青少年编程与数学 02-009 Django 5 Web 编程 20课题、测试 一、软件测试二、自动化测试三、单元测试四、Django 单元测试(一)、创建测试用例(二)、运行测试(三)、常用测试功能 课题摘要: 本文全面介绍了软件…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...

Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...

Qt的学习(二)
1. 创建Hello Word 两种方式,实现helloworld: 1.通过图形化的方式,在界面上创建出一个控件,显示helloworld 2.通过纯代码的方式,通过编写代码,在界面上创建控件, 显示hello world; …...
Cursor AI 账号纯净度维护与高效注册指南
Cursor AI 账号纯净度维护与高效注册指南:解决限制问题的实战方案 风车无限免费邮箱系统网页端使用说明|快速获取邮箱|cursor|windsurf|augment 问题背景 在成功解决 Cursor 环境配置问题后,许多开发者仍面临账号纯净度不足导致的限制问题。无论使用 16…...