【逆向】C与汇编的关系

程序1

使用 VC6.0 编译如下程序(使用 VC6.0 的原因是该编译器不会对代码进行过多的优化,因此适合逆向入门)

// 01.cpp : Defines the entry point for the console application.
//
# include "stdafx.h"int main(int argc, char* argv[]) {printf("Hello World!\n");return 0;
}

得到的程序使用 OllyICE 打开,找到 main 函数位置

image-20230118231216589

image-20230118231651147

可以看到 VC 将 printf 编译成了一个常量,也就是启用了全局堆来存放。

执行到 printf 后,右键选择在数据窗口跟随,可以看到该区段堆的结构

image-20230118232213674

image-20230118232313042

接下来修改程序

// 01.cpp : Defines the entry point for the console application.
//
# include "stdafx.h"int main(int argc, char* argv[]) {char buff[100] = {"sssssssssssss\0"};printf("Hello World!\n");return 0;
}

跟踪发现,VC 给程序分配了一段 0xA4 大小的堆栈空间,并且对这段空间进行了初始化

image-20230118233057366

选中寄存器区域的 ESP,右键在数据区跟随,到达堆栈。继续执行可以看到首先堆栈被初始化,然后分三次将 13 个 ‘s’ 写入内存

image-20230118233825260

程序2

再调试如下程序

// 01.cpp : Defines the entry point for the console application.
//
# include "stdafx.h"int main(int argc, char* argv[]) {int b = 0;b = 15;int i = b + 1;printf("Hello World!\n");return 0;
}

首先程序保存原来 EBP 的值,并分配新的堆栈空间。然后保存原来 EDI 的值,并分配新的数据区,使用rep指令对新数据区初始化。

image-20230118235718623

使用内联汇编的方式编写程序并编译

#include "stdafx.h"
#include <windows.h>int main(int argc, char* argv[]) {__asm{pushadpushfdMOV AL, 0xFFADD AL, 1popadpopfd}return 0;
}

可以看到,执行pushad会将所有寄存器的内容保存到栈里,执行pushfd会将所有标志位保存到栈里

image-20230119003246773

条件分支语句

下面再编译一个包含if-else的程序

#include "stdafx.h"
#include <windows.h>int main(int argc, char* argv[]) {int a = 1;if (a == 1) {printf("%d\n", 11);} else {printf("%d\n", 22);}return 0;
}

image-20230119004330522

内联汇编

下面演示如何内联汇编。打开一段比较复杂的程序,比如 Wechat Setup.exe,跳过开头很多程序入口,假设想要使用如下一段汇编指令的原生态代码

image-20230119102103005

cdq
shld    edx,eax,0x10
shl     eax,0x10
mov     edi,eax
xor     esi,esi

接下来打开 VC2008,新建项目;勾选Visual C+±控制台应用程序,勾选预编译头;右键左侧项目名,选择属性-配置属性-C/C+±代码生成-运行时库,选择多线程(/MT),这样就可以将 VC 库打到 exe 文件里去了;使用 VC2008 生成可执行文件。

image-20230119103718790

// 04.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>int __declspec (naked) Plus() {__asm{pushadcdqshld    edx,eax,0x10shl     eax,0x10mov     edi,eaxxor     esi,esipopad}
}int _tmain(int argc, _TCHAR* argv[])
{Plus();return 0;
}

可以看到 VC2008 编译出文件的入口位置与 VC6.0 完全不一样

image-20230119104025070

找到唯一一个 call 语句后设置断点并步入,在下面找到 wmainCRTStartup,双击跳转

image-20230119104730172

双击 jump 语句跳转

image-20230119104906015

找到我们的 main 函数,并双击跳转

image-20230119105040207

image-20230119105106958

再双击跳转

image-20230119105208097

双击 call 指令跳转,找到我们定义的 Plus 函数

image-20230119105318508

双击跳转,找到我们写的裸函数内容

image-20230119105407198

可以看到完全没有堆栈初始化等内容,也就是说使用 naked 定义的裸函数,所有的堆栈初始化、保护恢复现场等,都是由我们自己来决定的。我们尝试不适用裸函数来定义一个函数。

#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>int Plus() {int x = x + 1;return 1;
}int _tmain(int argc, _TCHAR* argv[])
{Plus();return 0;
}

image-20230119110445297

image-20230119110554895

image-20230119110620371

image-20230119110636209

image-20230119110709587

可以看到编译器承包了所有工作。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode第32题 : 最长有效括号

题目介绍 给你一个只包含 ( 和 ) 的字符串&#xff0c;找出最长有效&#xff08;格式正确且连续&#xff09;括号子串的长度。 示例 1&#xff1a; 输入&#xff1a;s "(()" 输出&#xff1a;2 解释&#xff1a;最长有效括号子串是 "()" 示例 2&#xf…

智能语音信息处理团队EMNLP 2023入选论文解析

2023年12月6日至10日&#xff0c;自然语言处理领域顶会EMNLP 2023在新加坡举行。语音及语言信息处理国家工程研究中心智能语音信息处理团队共3篇论文被会议主会及Findings接收&#xff0c;论文方向涵盖多方对话、大语言模型应用、小说理解等&#xff0c;各接收论文解读见后文。…

.NET Core NPOI导出复杂Excel

一、引入NPOI NuGet&#xff1a; NPOI GitHub源码地址&#xff1a; GitHub - tonyqus/npoi: a .NET library that can read/write Office formats without Microsoft Office installed. No COM, no interop. 版本说明&#xff1a; NPOI 2.4.1 &#xff08;注意不同版本可能使用…

k8s的二进制部署(二)网络

节点部署完成之后,节点的状态都是Notready&#xff0c;所以要部署k8s网络&#xff1a; k8s的网络类型&#xff1a; k8s中的通信模式&#xff1a; pod内部之间容器与容器之间的通信。 在同一个pod中的容器共享资源和网络&#xff0c;使用同一个网络命名空间&#xff0c;可以直…

【并发设计模式】聊聊Thread-Per-Message与Worker-Thread模式

在并发编程中&#xff0c;核心就是同步、互斥、分工。 同步是多个线程之间按照一定的顺序进行执行&#xff0c;比如A执行完&#xff0c;B在执行。而互斥是多个线程之间对于共享资源的互斥。两个侧重点不一样&#xff0c;同步关注的是执行顺序&#xff0c;互斥关注的是资源的排…

【vue3】-

创建vue3工程 在终端输入以下命令&#xff0c;根据自己的需求做出相应的选择&#xff1a; 生成的项目文件作用&#xff1a; extensions.json&#xff1a;插件 favicon.ico&#xff1a;页签图标 env.d.ts&#xff1a;ts不认识.css .html .txt .js……文件&#xff0c;这个文件…

微信支付产品种类

前言 微信支付产品共有6种形式&#xff0c;详情可参考 支付产品 支付产品 1. 付款码支付 用户展示微信钱包内的 “付款码”给商家&#xff0c;商家扫描后直接完成支付&#xff0c;适用于线下面对面收银场景。 2. JSAPI 支付 JSAPI 支付是指商户通过调用微信支付提供的接…

Jenkins基础教程

目录 第一章、快速了解Jenkins1.1&#xff09;Jenkins中一些概念介绍1.2&#xff09;Jenkins和maven用途上的区别1.3&#xff09;为什么使用Jenkins1.4&#xff09;学习过程中的疑问 第二章、安装Jenkins2.1&#xff09;安装之前的准备2.2&#xff09;Windows中Jenkins下载安装…

arm64 UAO/PAN 特性对用户空间边界读写的影响(copy_from/to_user)

文章目录 1 UAO/PAN 特性由来2 硬件PAN的支持3 UAO 的支持 1 UAO/PAN 特性由来 linux 内核空间与用户空间通过 copy_from/to_user 进行数据拷贝交换&#xff0c;而不是通过简单的 memcpy/strcpy 进行拷贝复制&#xff0c;原因是安全问题&#xff08;这里不详细展开&#xff09…

小白入门java基础-注解

一&#xff1a;介绍 Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的高级程序设计语言。 Java 可运行于多个平台&#xff0c;如 Windows, Mac OS 及其他多种 UNIX 版本的系统。Java语言编写的程序&#xff0c;在一次编译后&#xff0c;可以在多个系统平台上运行。 主…

开关电源输入输出电压测试方法:如何用开关电源智能测试系统测试输入输出电压?

一、用万用表测量输入输出电压 1. 连接万用表到电路中 2. 将万用表调到直流电压挡&#xff0c;连接红表笔到开关电源正极&#xff0c;连接黑表笔到开关电源负极。 3. 打开电源&#xff0c;读取万用表显示的电压值。 二、用示波器测量输入输出电压 1. 连接示波器到电路中 2. 将示…

「Qt Widget中文示例指南」如何实现一个日历?(一)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 本文中的CalendarWi…