debug - 打补丁 - 浮点数加法

文章目录

    • debug - 打补丁 - 浮点数加法
    • 概述
    • 笔记
    • demo
    • 用CE查看汇编(x64debug)
    • main()
    • update_info()
    • 快捷键 - CE中查看代码时的导航
    • 打补丁的时机 - 浮点数加法
    • 补丁代码
    • 补丁效果
    • 浮点数寄存器组的保存
    • END

debug - 打补丁 - 浮点数加法

概述

在cm中, UI上显示的数值仅仅用来显示, 改这个显示值没用.
显示时, 是从一个结构体中取出值(浮点数), 然后转成整数显示.
写了一个demo(vs2019 + console + debug/x64), 模拟结构体信息中的浮点数赋值和浮点数的显示.
用CE来看, 和cm中取值显示的汇编实现很像.
拿自己写的demo, 来打个补丁, 让显示之前, 先对结构体中的浮点值加上一些额外的值, 然后再去显示
这样的话, 显示值和结构体中的值就一致了.

笔记

demo

/*!
* \file fDataOpt.cpp
* \brief 测试在汇编中的浮点数操作的打补丁(浮点加法)
*/

#include <windows.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cstdint>

typedef struct _tag_info
{
	int id;
	float money;
} TAG_INFO;

void init();
int rand_ranged(int range_min, int range_max);
void update_info(TAG_INFO& info);

int main()
{
	TAG_INFO info;

	memset(&info, 0, sizeof(info));
	init();

	do {
		Sleep(1000);

		update_info(info);
		printf("money = %d\n", (int)info.money);
		if (info.money >= 9999) {
			break;
		}
	} while (true);

	system("pause");
	return 0;
}

void update_info(TAG_INFO& info)
{
	info.id = 0x1000;

	info.money += (float)rand_ranged(1, 10);
}

void init()
{
	srand(0215);
}

int rand_ranged(int range_min, int range_max)
{
	// Generate random numbers in the interval [range_min, range_max], inclusive.

	// Note: This method of generating random numbers in a range isn't suitable for
	// applications that require high quality random numbers.
	// rand() has a small output range [0,32767], making it unsuitable for
	// generating random numbers across a large range using the method below.
	// The approach below also may result in a non-uniform distribution.
	// More robust random number functionality is available in the C++ <random> header.
	// See https://learn.microsoft.com/cpp/standard-library/random

	return (int)(((double)rand() / RAND_MAX) * (range_max - range_min) + range_min);
}

用CE查看汇编(x64debug)

main()


fDataOpt.main - 40 55                 - push rbp
fDataOpt.main+2- 57                    - push rdi
fDataOpt.main+3- 48 81 EC 08010000     - sub rsp,00000108 { 264 }
fDataOpt.main+A- 48 8D 6C 24 20        - lea rbp,[rsp+20]
fDataOpt.main+F- 48 8D 7C 24 20        - lea rdi,[rsp+20]
fDataOpt.main+14- B9 0A000000           - mov ecx,0000000A { 10 }
fDataOpt.main+19- B8 CCCCCCCC           - mov eax,CCCCCCCC { -858993460 }
fDataOpt.main+1E- F3 AB                 - repe stosd 
fDataOpt.main+20- 48 8B 05 F1B50000     - mov rax,[fDataOpt.__security_cookie] { (192) }
fDataOpt.main+27- 48 33 C5              - xor rax,rbp
fDataOpt.main+2A- 48 89 85 D8000000     - mov [rbp+000000D8],rax
fDataOpt.main+31- 48 8D 0D ED050100     - lea rcx,[fDataOpt.exe+22015] { (1) }
fDataOpt.main+38- E8 52F9FFFF           - call fDataOpt.exe+1137F
fDataOpt.main+3D- 41 B8 08000000        - mov r8d,00000008 { 8 }
fDataOpt.main+43- 33 D2                 - xor edx,edx
fDataOpt.main+45- 48 8D 4D 08           - lea rcx,[rbp+08]
fDataOpt.main+49- E8 92F8FFFF           - call fDataOpt.exe+112D0 { memset()
 }
fDataOpt.main+4E- E8 66F7FFFF           - call fDataOpt.exe+111A9 { init()
 }
fDataOpt.main+53- B9 E8030000           - mov ecx,000003E8 { 1000 }
fDataOpt.main+58- FF 15 B2F50000        - call qword ptr [fDataOpt._imp_Sleep] { ->KERNEL32.Sleep }
fDataOpt.main+5E- 48 8D 4D 08           - lea rcx,[rbp+08]
fDataOpt.main+62- E8 9DF7FFFF           - call fDataOpt.exe+111F4 { update_info()
 }
fDataOpt.main+67- F3 0F2C 45 0C         - cvttss2si eax,[rbp+0C] { 浮点数强转整数
 }
fDataOpt.main+6C- 8B D0                 - mov edx,eax
fDataOpt.main+6E- 48 8D 0D 43920000     - lea rcx,[fDataOpt.exe+1ACA8] { ("money = %d
") }
fDataOpt.main+75- E8 30F7FFFF           - call fDataOpt.exe+1119A { printf()
 }
fDataOpt.main+7A- F3 0F10 45 0C         - movss xmm0,[rbp+0C] { 载入浮点数
 }
fDataOpt.main+7F- 0F2F 05 56920000      - comiss xmm0,[fDataOpt.exe+1ACCC] { (9999.00) }
fDataOpt.main+86- 72 02                 - jb fDataOpt.main+8A
fDataOpt.main+88- EB 07                 - jmp fDataOpt.main+91
fDataOpt.main+8A- 33 C0                 - xor eax,eax
fDataOpt.main+8C- 83 F8 01              - cmp eax,01 { 1 }
fDataOpt.main+8F- 75 C2                 - jne fDataOpt.main+53
fDataOpt.main+91- 48 8D 0D 30920000     - lea rcx,[fDataOpt.exe+1ACB8] { ("pause") }
fDataOpt.main+98- FF 15 3AF80000        - call qword ptr [fDataOpt._imp_system] { ->ucrtbased.system }
fDataOpt.main+9E- 33 C0                 - xor eax,eax
fDataOpt.main+A0- 8B F8                 - mov edi,eax
fDataOpt.main+A2- 48 8D 4D E0           - lea rcx,[rbp-20]
fDataOpt.main+A6- 48 8D 15 E3910000     - lea rdx,[fDataOpt.exe+1AC80] { (1) }
fDataOpt.main+AD- E8 79F8FFFF           - call fDataOpt.exe+1131B
fDataOpt.main+B2- 8B C7                 - mov eax,edi
fDataOpt.main+B4- 48 8B 8D D8000000     - mov rcx,[rbp+000000D8]
fDataOpt.main+BB- 48 33 CD              - xor rcx,rbp
fDataOpt.main+BE- E8 05F7FFFF           - call fDataOpt.exe+111B8
fDataOpt.main+C3- 48 8D A5 E8000000     - lea rsp,[rbp+000000E8]
fDataOpt.main+CA- 5F                    - pop rdi
fDataOpt.main+CB- 5D                    - pop rbp
fDataOpt.main+CC- C3                    - ret 
fDataOpt.exe+11ABD- CC                    - int 3 

update_info()

fDataOpt.update_info - 48 89 4C 24 08        - mov [rsp+08],rcx { rcx是结构体指针
 }
fDataOpt.update_info+5- 55                    - push rbp
fDataOpt.update_info+6- 57                    - push rdi
fDataOpt.update_info+7- 48 81 EC E8000000     - sub rsp,000000E8 { 232 }
fDataOpt.update_info+E- 48 8D 6C 24 20        - lea rbp,[rsp+20]
fDataOpt.update_info+13- 48 8D 0D 6B070100     - lea rcx,[fDataOpt.exe+22015] { (1) }
fDataOpt.update_info+1A- E8 D0FAFFFF           - call fDataOpt.exe+1137F
fDataOpt.update_info+1F- 48 8B 85 E0000000     - mov rax,[rbp+000000E0] { rbp + 0xE0 也是结构体指针
 }
fDataOpt.update_info+26- C7 00 00100000        - mov [rax],00001000 { 4096 }
fDataOpt.update_info+2C- BA 0A000000           - mov edx,0000000A { 10 }
fDataOpt.update_info+31- B9 01000000           - mov ecx,00000001 { 1 }
fDataOpt.update_info+36- E8 80F7FFFF           - call fDataOpt.exe+1104B { 产生随机数(1~10)
 }
fDataOpt.update_info+3B- F3 0F2A C0            - cvtsi2ss xmm0,eax { eax是返回的随机数
cvtsi2ss 是将4字节内容整型内容, 强转为浮点数(e.g. 1 => 1.0f)
 }
fDataOpt.update_info+3F- 48 8B 85 E0000000     - mov rax,[rbp+000000E0] { rbp + 0xE0是结构体指针
 }
fDataOpt.update_info+46- F3 0F10 48 04         - movss xmm1,[rax+04] { 将info.money给xmm1
 }
fDataOpt.update_info+4B- F3 0F58 C8            - addss xmm1,xmm0 { 2个浮点数相加
 }
fDataOpt.update_info+4F- 0F28 C1               - movaps xmm0,xmm1 { 浮点数拷贝
 }
fDataOpt.update_info+52- 48 8B 85 E0000000     - mov rax,[rbp+000000E0]
fDataOpt.update_info+59- F3 0F11 40 04         - movss [rax+04],xmm0 { 浮点数转为2进制存储, 更新money
 }
fDataOpt.update_info+5E- 48 8D A5 C8000000     - lea rsp,[rbp+000000C8]
fDataOpt.update_info+65- 5F                    - pop rdi
fDataOpt.update_info+66- 5D                    - pop rbp
fDataOpt.update_info+67- C3                    - ret 
fDataOpt.update_info+68- CC                    - int 3 


看了汇编实现, 就大概知道怎么给显示前的值打补丁(浮点加法)

快捷键 - CE中查看代码时的导航

在这里插入图片描述
如果不知道导航键, 在查看代码时, 无法回到查看的原始点. 只能按F8执行一步, 那样太麻烦了, 耽误事.

打补丁的时机 - 浮点数加法

在这里插入图片描述
在浮点数更新完, 即将要显示的时候, 打补丁.
打完补丁后, 浮点数增加了, 再执行原始的取浮点数的汇编代码.

补丁代码

[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,2048,"fDataOpt.exe"+11A57) 
label(returnhere)
label(originalcode)
label(exit)

newmem: //this is allocated memory, you have read,write,execute access
//place your code here

// save env
push rax

// do task
movss xmm1, [rbp+0x0C] // 将info.money给xmm1

// 在原始值上加100(CE的汇编写法中, 数字默认都是16进制)
mov eax, 0x64
cvtsi2ss xmm0,eax // eaxcvtsi2ss 是将4字节内容整型内容, 强转为浮点数(e.g. 1 => 1.0f)

addss xmm1,xmm0 // 2个浮点数相加

movss [rbp+0x0C], xmm1 // 更新改过的info.money到info结构体

// restore env
pop rax

originalcode:
cvttss2si eax,[rbp+0C]

exit:
jmp returnhere

"fDataOpt.exe"+11A57:
jmp newmem
returnhere:


 
 
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
"fDataOpt.exe"+11A57:
db F3 0F 2C 45 0C
//cvttss2si eax,[rbp+0C]

补丁效果

money = 96
money = 99
money = 108
money = 112
money = 118 // 这里是原始的实现, 每次money增加1~10
money = 224 // < 从这开始, 加了补丁, 每次money额外增加了100
money = 333
money = 436
money = 543
money = 652

浮点数寄存器组的保存

模拟了一下, 只看到浮点数寄存器组的保存, 没看到浮点数寄存器组的恢复.
等后续再看看哪里能看到浮点数寄存器的恢复, 或者用CE写个补丁试试. 估计就是用movss就行了.

		// 模拟一下函数外边有浮点数, 函数参数也传浮点数, 函数内部也进行浮点数操作
		// 看看汇编代码如何保存和恢复浮点寄存器组?
		f3 = f1 + f2;
		f4 = f1 - f2;
		f5 = test_xmmx(f1, f2, f3, f4);
		printf("f5 = %.2f\n", f5);

	} while (true);

	system("pause");
	return 0;
}

float test_xmmx(float& f1, float& f2, float f3, float f4)
{
	float f_rc = (f1 + f2) * f3 / f4;
	return f_rc;
}

		// 模拟一下函数外边有浮点数, 函数参数也传浮点数, 函数内部也进行浮点数操作
		// 看看汇编代码如何保存和恢复浮点寄存器组?
		f3 = f1 + f2;
00007FF629391B48  movss       xmm0,dword ptr [f1]  
00007FF629391B4D  addss       xmm0,dword ptr [f2]  
00007FF629391B52  movss       dword ptr [f3],xmm0  
		f4 = f1 - f2;
00007FF629391B57  movss       xmm0,dword ptr [f1]  
00007FF629391B5C  subss       xmm0,dword ptr [f2]  
00007FF629391B61  movss       dword ptr [f4],xmm0  
		f5 = test_xmmx(f1, f2, f3, f4);
00007FF629391B69  movss       xmm3,dword ptr [f4]  
00007FF629391B71  movss       xmm2,dword ptr [f3]  
00007FF629391B76  lea         rdx,[f2]  
00007FF629391B7A  lea         rcx,[f1]  
00007FF629391B7E  call        test_xmmx (07FF6293913B1h)  
00007FF629391B83  movss       dword ptr [f5],xmm0  
		printf("f5 = %.2f\n", f5);
00007FF629391B8B  cvtss2sd    xmm0,dword ptr [f5]  
00007FF629391B93  movaps      xmm1,xmm0  
00007FF629391B96  movq        rdx,xmm1  
00007FF629391B9B  lea         rcx,[string "f5 = %.2f\n" (07FF62939AD50h)]  
00007FF629391BA2  call        printf (07FF62939119Ah)  

	} while (true);
--- D:\my_dev\my_local_git_prj\study\asm\case\fxmmxOpt\fDataOpt.cpp ------------

float test_xmmx(float& f1, float& f2, float f3, float f4)
{
00007FF6293918A0  movss       dword ptr [rsp+20h],xmm3  // 保存浮点数寄存器
00007FF6293918A6  movss       dword ptr [rsp+18h],xmm2  
00007FF6293918AC  mov         qword ptr [rsp+10h],rdx  
00007FF6293918B1  mov         qword ptr [rsp+8],rcx  
00007FF6293918B6  push        rbp  
00007FF6293918B7  push        rdi  
00007FF6293918B8  sub         rsp,118h  
00007FF6293918BF  lea         rbp,[rsp+30h]  
00007FF6293918C4  lea         rcx,[__E9A00158_fDataOpt@cpp (07FF6293A2015h)]  
00007FF6293918CB  call        __CheckForDebuggerJustMyCode (07FF62939137Fh)  
	float f_rc = (f1 + f2) * f3 / f4;
00007FF6293918D0  mov         rax,qword ptr [f1]  
00007FF6293918D7  mov         rcx,qword ptr [f2]  
00007FF6293918DE  movss       xmm0,dword ptr [rax]  
00007FF6293918E2  addss       xmm0,dword ptr [rcx]  // 浮点数加法
00007FF6293918E6  mulss       xmm0,dword ptr [f3]  // 浮点数乘法
00007FF6293918EE  divss       xmm0,dword ptr [f4]  // 浮点数除法
00007FF6293918F6  movss       dword ptr [f_rc],xmm0  
	return f_rc;
00007FF6293918FB  movss       xmm0,dword ptr [f_rc]  
}
00007FF629391900  lea         rsp,[rbp+0E8h]  
00007FF629391907  pop         rdi  
00007FF629391908  pop         rbp  
00007FF629391909  ret  

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/389597.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开启AI新篇章:全新GPT-4订阅方案! ChatGPTPlus(GPT4)支付渠道! 付费充值!

1. GPT-4订阅价格 以每月仅20美元的价格&#xff0c;引领您进入GPT-4的强大数字体验世界。作为前沿的语言模型&#xff0c;GPT-4为您的工作和创造带来了无与伦比的生产力提升&#xff0c;彻底改变您的工作和创造方式。 GPT-4不仅具有卓越的自然语言处理能力&#xff0c;还引入…

kafka如何保证消息不丢?

概述 我们知道Kafka架构如下&#xff0c;主要由 Producer、Broker、Consumer 三部分组成。一条消息从生产到消费完成这个过程&#xff0c;可以划分三个阶段&#xff0c;生产阶段、存储阶段、消费阶段。 产阶段: 在这个阶段&#xff0c;从消息在 Producer 创建出来&#xff0c;…

【汇总】解决IndexedDB报Failed to execute ‘transaction‘ on ‘IDBDatabase‘

问题发现 再学习HTML5中&#xff0c;有介绍到 Web 存储&#xff0c;当代码编写完成后&#xff0c;运行报错 Failed to execute ‘transaction’ on ‘IDBDatabase’: One of the specified object stores was not found. 示例代码如下&#xff1a; <!DOCTYPE html> <…

【后端高频面试题--Nginx篇】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;后端高频面试题 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 后端高频面试题--Nginx篇 往期精彩内容什么是Nginx&#xff1f;为什么要用Nginx&#xff1f;为…

HC05蓝牙模块

简介 HC-05 蓝牙串口通信模块&#xff0c;是基于 Bluetooth Specification V2.0 带 EDR 蓝牙协议的 数传模块。无线工作频段为 2.4GHz ISM&#xff0c;调制方式是 GFSK。模块最大发射功率为 4dBm&#xff0c;接收灵敏度-85dBm&#xff0c;板载 PCB 天线&#xff0c;可以实现 1…

HTTP协议-响应报文详解(Respond)

目录 前言&#xff1a; 1.Respond报文 1.1报文格式 1.2格式图解 2.状态行&#xff08;首行&#xff09; 2.1状态码/状态码解释 &#xff08;1&#xff09;200 OK &#xff08;2&#xff09;404 Not Found &#xff08;3&#xff09;403 Forbidden &#xff08;4&#…

【机器学习笔记】 6 机器学习库Scikit-learn

Scikit-learn概述 Scikit-learn是基于NumPy、 SciPy和 Matplotlib的开源Python机器学习包,它封装了一系列数据预处理、机器学习算法、模型选择等工具,是数据分析师首选的机器学习工具包。 自2007年发布以来&#xff0c;scikit-learn已经成为Python重要的机器学习库了&#xff…

C++中类的6个默认成员函数 【拷贝构造函数】

文章目录 拷贝构造函数的使用拷贝构造对于自定义类型【浅拷贝】深拷贝拷贝构造函数典型调用场景 拷贝构造函数的使用 在前几章学习对象的时候&#xff0c;我们有的时候需要一个与已存在对象一某一样的新对象 那在创建对象时&#xff0c;可否创建一个与已存在对象一某一样的新对…

数值类型的运算方式总结

提纲1&#xff1a;常见的位运算使用场景 提纲2&#xff1a;整数类型运算时的类型溢出问题&#xff0c;产生原因以及解决办法 提纲3&#xff1a;浮点类型运算时的精度丢失问题&#xff0c;产生原因以及解决办法 数值类型&#xff08;6种&#xff09;分为&#xff1a; 整型&…

简易绘图软件(水一期)

哈哈&#xff01; 1、编写代码&#xff1a; 代码&#xff1a; main: #include <graphics.h> #include <music.h> #include <heker.h> #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )using…

【python】python入门(输出)

本篇文章将会介绍关于python的常见输出&#xff0c;希望对您有帮助&#xff01; 输出 用到print函数 print(oh mygod)##或者 print("oh mygod")##或者 print("oh"" ""mygod") 输出结果&#xff1a; 用单引号、双引号都可以 ,引号中可…

单片机学习笔记---LCD1602

LCD1602介绍 LCD1602&#xff08;Liquid Crystal Display&#xff09;液晶显示屏是一种字符型液晶显示模块&#xff0c;可以显示ASCII码的标准字符和其它的一些内置特殊字符&#xff08;比如日文的片假名&#xff09;&#xff0c;还可以有8个自定义字符 显示容量&#xff1a;…

Linux 幻兽帕鲁服务器怎么上传存档文件?

通过控制台远程连接到 Linux 服务器后&#xff0c;你可以打开文件树&#xff0c;然后找到幻兽帕鲁存档位置&#xff0c;将存档压缩包上传到 Pal 目录中。 记得替换存档前要先停止服务。 2. 然后将 Saved.tar 文件解压&#xff0c;并完全替换新服务器上的 Saved 存档目录即可。 …

蓝桥杯:C++排序

排序 排序和排列是算法题目常见的基本算法。几乎每次蓝桥杯软件类大赛都有题目会用到排序或排列。常见的排序算法如下。 第(3)种排序算法不是基于比较的&#xff0c;而是对数值按位划分&#xff0c;按照以空间换取时间的思路来排序。看起来它们的复杂度更好&#xff0c;但实际…

真假难辨 - Sora(OpenAI)/世界模拟器的技术报告

目录 引言技术报告汉译版英文原版 引言 Sora是OpenAI在2024年2月15日发布的世界模拟器&#xff0c;功能是通过文本可以生成一分钟的高保真视频。由于较高的视频质量&#xff0c;引起了巨大关注。下面是三个示例&#xff0c;在示例之后给出了其技术报告&#xff1a; tokyo-wal…

博途PLC While指令编程应用(SCL代码)

FOR循环和While指令都可以实现循环控制。在循环体内部&#xff0c;你可以编写需要重复执行的代码。WhIile在每次循环开始之前&#xff0c;都会检查条件是否为真。如果条件为真&#xff0c;则执行循环体内的代码&#xff1b;如果条件为假&#xff0c;则跳出循环&#xff0c;继续…

Android Studio 实现图书借阅(管理)系统

&#x1f345;文章末尾有获取完整项目源码方式&#x1f345; 目录 前言 一、任务介绍 1.1 背景 1.2目的和意义 二、 实现介绍 视频演示 2.1 启动页实现 2.2 注册页面实现 2.3 登陆页面实现 2.4 图书列表的实现 2.5 当前借阅页面实现 2.6 我的页面实现…

你知道.NET的字符串在内存中是如何存储的吗?

一、字符串对象的内存布局 从“值类型”和“引用类型”来划分&#xff0c;字符串自然属于引用类型的范畴&#xff0c;所以一个字符串对象自然采用引用类型的内存布局。引用类型实例的内存布局总的来说整个内存布局分三块&#xff1a;ObjHeader TypeHandle Payload。对于一般…

如何在Windows中配置多个显示器?这里提供详细步骤

Windows可以通过多种方式使用多个显示器,扩展或复制主显示器。你甚至可以关闭主显示器。以下是如何使用简单的键盘快捷键更改辅助显示设置。 使用Windows+P投影菜单 要快速更改Windows 10处理多个显示器的方式,请按Windows+P。屏幕右侧会弹出一个名为“投影”的深灰色菜单。…

Codeforces Round 926 F. Sasha and the Wedding Binary Search Tree

F. Sasha and the Wedding Binary Search Tree 题意 给定一颗二叉搜索树&#xff0c;规定树上的所有点的点权都在范围 [ 1 , C ] [1, C] [1,C] 内&#xff0c;树上的某些节点点权已知&#xff0c;某些节点点权未知&#xff0c;求出合法的二叉搜索树的数量 思路 由于是二叉搜…