浮点指令之找main函数
环境
vs2019 编译选项x86(32位) debug版本
float指令练习
//c++源码
#include<stdio.h>
int main(int argc,char* argv)
{
float f = (float)argc;//将int类型转换为float
printf("%f",f);
argc = (int)f;//在将float类型转换为int
printf("%d",argc);
return 0;
}
编译运行后,在return 0;语句打一个断点,右键可以看到切到汇编代码
对应的汇编代码如下
00183E40 55 push ebp
00183E41 8B EC mov ebp,esp
00183E43 81 EC CC 00 00 00 sub esp,0CCh
00183E49 53 push ebx
00183E4A 56 push esi
00183E4B 57 push edi
00183E4C 8D 7D F4 lea edi,[ebp-0Ch]
00183E4F B9 03 00 00 00 mov ecx,3
00183E54 B8 CC CC CC CC mov eax,0CCCCCCCCh
00183E59 F3 AB rep stos dword ptr es:[edi]
00183E5B B9 03 C0 18 00 mov ecx,offset _78F0D3D6_helloworld@c (018C003h)
00183E60 E8 A2 D4 FF FF call @__CheckForDebuggerJustMyCode@4 (0181307h)
4: float f = (float)argc;
00183E65 F3 0F 2A 45 08 cvtsi2ss xmm0,dword ptr [argc] //[argc]对应是[ebp+8] cvsi2ss指令:将整数转换为单精度数int强制转为float
00183E6A F3 0F 11 45 F8 movss dword ptr [f],xmm0//[f] 对应的是[ebp-4] //movss指令:用来传送单精度数,用来转送float
5: printf("%f",f);
00183E6F F3 0F 5A 45 F8 cvtss2sd xmm0,dword ptr [f]
00183E74 83 EC 08 sub esp,8
00183E77 F2 0F 11 04 24 movsd mmword ptr [esp],xmm0//movsd指令:传送双精度数
00183E7C 68 CC 7B 18 00 push offset string "%f" (0187BCCh)
00183E81 E8 17 D5 FF FF call _printf (018139Dh)
00183E86 83 C4 0C add esp,0Ch //外平栈
6: argc = (int)f;
00183E89 F3 0F 2C 45 F8 cvttss2si eax,dword ptr [f]//cvttss2si将float类型转换为int类型
00183E8E 89 45 08 mov dword ptr [argc],eax
7: printf("%d",argc);
00183E91 8B 45 08 mov eax,dword ptr [argc]
00183E94 50 push eax
00183E95 68 D0 7B 18 00 push offset string "%d" (0187BD0h)
00183E9A E8 FE D4 FF FF call _printf (018139Dh)
00183E9F 83 C4 08 add esp,8
8: return 0;
00183EA2 33 C0 xor eax,eax
9: }
00183EA4 5F pop edi
00183EA5 5E pop esi
00183EA6 5B pop ebx
00183EA7 81 C4 CC 00 00 00 add esp,0CCh
00183EAD 3B EC cmp ebp,esp
00183EAF E8 7C D3 FF FF call __RTC_CheckEsp (0181230h)
00183EB4 8B E5 mov esp,ebp
00183EB6 5D pop ebp
00183EB7 C3 ret
上面的代码:浮点数与整数、整数与浮点数的相互转换,从上面可以看到float类型占4字节,但是使用浮点栈将以8字节方式进行处理(movsd),而使用媒体寄存器则以4字节处理。当浮点数作为参数时,并不能直接入栈,PUSH指令只能传入4字节数据到栈。这样会丢失4字节数据。这就是使用printf函数以整数方式输出浮点数时会产生错误的原因。printf以整数方式输出时,将对应参数作为4字节数据长度,按补码范式解释,而真正压入的参数为浮点类型时,却是8字节长度,需要按浮点编码范式解释。
如何找到main函数
在大学中我们老师都教授我们一个函数的入口函数是main,但是呢今天我们来看看到底是不是。拿出工具x32dbug来进行测试
第一步

第二步进来以后初始的状态

是一个ntdll.dll是重要的Windows NT内核级文件。描述了windows本地NTAPI的接口。当Windows启动时,ntdll.dll就驻留在内存中特定的写保护区域,使别的程序无法占用这个内存区域。
第三步 快捷按F9

我们可以看到是一个._mainCRTStartup>,那么我们在进去(F9)
第三步

.__scrt_common main>,我们再次进去(F9)
第四步

_scrt_common_main_seh>
第五步

其中包含了.main函数,那么我们就算找到了main
00183E4 | 55 | push ebp | helloworld.c:3
00183E4 | 8BEC | mov ebp,esp |
00183E4 | 81EC CC000000 | sub esp,CC |
00183E4 | 53 | push ebx |
00183E4 | 56 | push esi | esi:__enc$textbss$end+23
00183E4 | 57 | push edi | edi:__enc$textbss$end+23
00183E4 | 8D7D F4 | lea edi,dword ptr ss:[ebp-C] | edi:__enc$textbss$end+23
00183E4 | B9 03000000 | mov ecx,3 |
00183E5 | B8 CCCCCCCC | mov eax,CCCCCCCC | eax:&"E:\\c++反汇编技术加密与解密\\shujutype\\Debug\\shujutype.exe"
00183E5 | F3:AB | rep stosd |
00183E5 | B9 03C01800 | mov ecx,<shujutype._78F0D3D6_helloworld@c> | helloworld.c:15732480
00183E6 | E8 A2D4FFFF | call shujutype.181307 |
00183E6 | F3:0F2A45 08 | cvtsi2ss xmm0,dword ptr ss:[ebp+8] | helloworld.c:4
00183E6 | F3:0F1145 F8 | movss dword ptr ss:[ebp-8],xmm0 | [ebp-8]:&"E:\\c++反汇编技术加密与解密\\shujutype\\Debug\\shujutype.exe"
00183E6 | F3:0F5A45 F8 | cvtss2sd xmm0,dword ptr ss:[ebp-8] | helloworld.c:5, [ebp-8]:&"E:\\c++反汇编技术加密与解密\\shujutype\\Debug\\shujutype.exe"
00183E7 | 83EC 08 | sub esp,8 |
00183E7 | F2:0F110424 | movsd qword ptr ss:[esp],xmm0 |
00183E7 | 68 CC7B1800 | push shujutype.187BCC |
00183E8 | E8 17D5FFFF | call shujutype.18139D |
00183E8 | 83C4 0C | add esp,C |
00183E8 | F3:0F2C45 F8 | cvttss2si eax,dword ptr ss:[ebp-8] | helloworld.c:6, [ebp-8]:&"E:\\c++反汇编技术加密与解密\\shujutype\\Debug\\shujutype.exe"
00183E8 | 8945 08 | mov dword ptr ss:[ebp+8],eax |
00183E9 | 8B45 08 | mov eax,dword ptr ss:[ebp+8] | helloworld.c:7
00183E9 | 50 | push eax | eax:&"E:\\c++反汇编技术加密与解密\\shujutype\\Debug\\shujutype.exe"
00183E9 | 68 D07B1800 | push shujutype.187BD0 |
00183E9 | E8 FED4FFFF | call shujutype.18139D |
00183E9 | 83C4 08 | add esp,8 |
00183EA | 33C0 | xor eax,eax | helloworld.c:8, eax:&"E:\\c++反汇编技术加密与解密\\shujutype\\Debug\\shujutype.exe"
00183EA | 5F | pop edi | helloworld.c:9, edi:__enc$textbss$end+23
00183EA | 5E | pop esi | esi:__enc$textbss$end+23
00183EA | 5B | pop ebx |
00183EA | 81C4 CC000000 | add esp,CC |
00183EA | 3BEC | cmp ebp,esp |
00183EA | E8 7CD3FFFF | call shujutype.181230 |
00183EB | 8BE5 | mov esp,ebp |
00183EB | 5D | pop ebp |
00183EB | C3 | ret |
与我们编译好的一摸一样,那么我们就可以确定是main函数
总结
main函数是语法规定的用户入口,而真正的入口函数是mainCRTStartup,mainCRTStarup再次调用main函数。
浮点指令之找main函数的更多相关文章
- 【逆向知识】VS程序反汇编找main函数
工具:OllyICE 调试快捷键说明: F2键:设置断点,只要在光标定位的位置 F4键:程序运行到光标处 F7键:单步步入.功能同单步步过(F8)类似,区别是遇到 CALL 等子程序时会进入其中,进入 ...
- exe怎么找main函数
先说DEBUG版本的命令行EXE main函数有两种,第一种是int main(),第二种是int main(int argc,char* argv[]) 不管哪种只要查找j___p___argc就能 ...
- 【逆向工具】IDA使用2-VS2015版本release查找main函数入口,局部变量
VS2015版本release查找main函数入口 vc++开发的程序main或WinMain函数是语法规定的用户入口,而不是应用程序入口.入口代码是mainCRTstartup.wmainCRTSt ...
- 06_传智播客iOS视频教程_源文件后缀名和main函数
OC与C语言的不同. 把OC程序运行起来,CPU只会找main函数.并且只会执行main函数当中的代码.当main函数的代码执行完毕之后这个程序就自动结束掉了. main函数的参数是可以让我们在运行程 ...
- 在有main函数的前提下 eclipse找不到主类
有时候在测试类的时候eclipse会莫名奇妙的提示找不到主类 接下来分别有几种解决办法 1.在项目上右击> Builder Path -> Configure Build Path - ...
- [汇编与C语言关系]2. main函数与启动例程
为什么汇编程序的入口是_start,而C程序的入口是main函数呢?以下就来解释这个问题 在<x86汇编程序基础(AT&T语法)>一文中我们汇编和链接的步骤是: $ as hell ...
- main函数和启动例程
为什么汇编程序的入口是_start,而C程序的入口是main函数呢?本节就来解释这个问题.在讲例 18.1 “最简单的汇编程序”时,我们的汇编和链接步骤是: $ as hello.s -o hello ...
- 为什么c程序里一定要写main函数
一. 学习过程 编写程序f.c: 对其进行编译,正常通过,再对其进行连接,出现错误: 显示的出错信息为: 翻译成中文是:在c0s模块没有定义符号’_main’. 那么这个错误信息可能与文件c0s.ob ...
- C语言编程漫谈——main函数
写在前面 促使我写这篇文章是因为我这几天找了几个一样是大三的同学,与我相同专业相同方向(物联网)的人,除了@小胡同的诗,基本没有什么其他人会现在看起来很简单的编程题目了.问了一下其他同学,他们大部分都 ...
- 通过启动函数定位main()函数
如下,通过vc6.0编写一个hello world程序.尝试结合汇编代码.分析启动函数找到main函数. 在printf(xxx)插入断点,调试执行.如下,在堆栈窗口中可见main()下的一个 ...
随机推荐
- Linux 查看内存使用情况的几种方法
*以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「ENG八戒」https://mp.weixin.qq.com/s/27UaVm5_FMhCnxB88pc0QA 在运行 Linux 系 ...
- 劲(很)霸(不)酷(好)炫(用)的NLP可视化包:Dodorio 使用指北
朋友们,朋友们,事情是这样的.最近心血来潮,突然想起很久以前看过的一个NLP可视化包.它的效果是下面这个样子: 在此之前,已经有一些文章从论文的角度对这个包进行了介绍,详情请见 推荐一个可交互的 At ...
- MySql中执行计划如何来的——Optimizer Trace
作者:京东物流 籍磊 1.前言 当谈到MySQL的执行计划时,会有很多同学想:"我就觉得使用其他的执行方案比EXPLAIN语句输出的方案强,凭什么优化器做的决定与我得不一样?".这 ...
- js计算当前时间差
1 function timesFun(timesData) { 2 //如果时间格式是正确的,那下面这一步转化时间格式就可以不用了 3 var dateBegin = new Date(timesD ...
- 如何实现一个sync.Once
sync.Once 是 golang里用来实现单例的同步原语.Once 常常用来初始化单例资源, 或者并发访问只需初始化一次的共享资源,或者在测试的时候初始化一次测试资源. 单例,就是某个资源或者对象 ...
- Prism Sample 4 View Discovery
前三节算是弄明白了Region是什么,但是定义了区域,怎样向区域中添加内容呢?内容是UserControl,即ViewA. 添加内容的方式有2种,一种叫View Discovery,一种叫View I ...
- ersync 实时同步
ersync 实时同步 目录 ersync 实时同步 实时同步概述 结合sersync+rsync实时同步实战 环境准备 部署sersync(客户端) 实时同步概述 什么是实时同步 实时同步是一种只要 ...
- get()、get_or_create()、first()、last()、latest()、earliest()、in_bulk()
get() 查询. get_or_create() 不存在时更新.存在时查询并返回. first() 获取第一笔. last() 获取最后一笔. 使用latest和earliest时需要在元数据(me ...
- Qt+QtWebApp开发笔记(四):http服务器使用Session和Cookie实现用户密码登录和注销功能
前言 前面实现了基础的跳转,那么动态交互中登录是常用功能. 本篇实现一个动态交互的简单登录和注销功能,在Qt中使用Session和Cookie技术. Demo 下载地址 链接:ht ...
- Factory Method Pattern 工厂方法模式简介与 C# 示例【创建型】【设计模式来了】
〇.简介 1.什么是工厂方法模式? 一句话解释: 实体类和工厂类均为单独实现,不影响已实现的类,方便扩展. 工厂方法模式(Factory Method Pattern)是一种创建型模式,它允许客户 ...