Win32程序入口识别,定位回调函数,具体事件处理的定位,ESP寻址方式,压栈方式复习

news2024/11/24 19:31:41

本专栏上一篇文章带领大家编写了第一个Windows程序,并且带领大家了解了Windows消息机制,如果大家还是不了解的话,可以到我的另一篇专栏中深入学习一下windows消息,Windows消息循环的原理,点击这里就可以查看啦。
我们在逆向别人的程序的时候,首先肯定要找到这个程序的入口,其次,当我们点击了某个按钮的时候,程序(回调函数)到底做了什么事情?程序入口识别,定位回调函数是我们必备的技能。这篇文章来带领大家找一下程序的入口,定位回调函数,并且带领大家了解ESP寻址方式,顺带再来复习一下压栈方式。

文章目录

  • 一.Win32程序入口识别
    • 调用约定
  • 二.定位回调函数
  • 三.浅析ESP寻址方式
  • 四.具体事件的处理定位

一.Win32程序入口识别

我们在使用OllyDbg,x64dbg等工具进行动态调试的时候,工具给我们的断点是PE文件结构中的EntryPoint,并不是真正的程序入口,在程序入口和EntryPoint之间,还有很多操作系统需要做的事,而我们很多时候并不需要关心,那我们就来找找真正的程序入口:

我们在编写一个Win32应用程序的时候,我们都会以WinMain函数作为入口点,那么在我们逆向程序的时候,也需要找到这个函数,也就是程序真正的入口了,我们先来复习一下WinMain函数,因为我们定位应用程序入口的时候,就需要WinMain函数的参数来帮助我们定位应用程序入口。

int APIENTRY WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nShowCmd
);

参数解释:

  • hInstance:应用程序的当前实例的句柄,我们在程序中接收,输出后发现,其实这个就是ImageBase
    hPrevInstance:应用程序的上一个实例的句柄。此参数始终为NULL。
    lpCmdLine:应用程序的命令行,不包括程序名称,实际上,我们在启动应用程序的时候,是可以给应用程序传一个参数的,而lpCmdLine就用于接收这个参数,我们一般不会用到。
    nShowCmd:控制程序的显示方式。

大家肯能对这里定义主函数前的APIENTRY不太了解,实际上这就是做了一个改名而已,我们来看看:
我们在VS中,选定APIENTRY,F12直接看看它的定义:

APIENTRY

我们发现APIENTRY是对WINAPI改了一个名字,我们追根到底,看看WINAPI到底是什么:

WINAPI

我们发现这里的WINAPI实际上是一种调用约定,我们在讲PE的时候,提到过,这里我也记得不是很清楚了,我们来复习一下几种调用约定:

调用约定

这里讲到的调用约定都是在汇编,C语言中我们常见的调用约定,也是我们逆向的时候最常见到的:

    1. _cdecl
      参数压栈顺序:从左至右入栈
      平衡堆栈方式:调用者自行清理堆栈
    1. _sedcall
      参数压栈顺序:从右至左入栈
      平衡堆栈方式:自身清理堆栈,调用者不用清理堆栈
    1. _fastcall:
      参数压栈顺序:ECX/EDX传送前两个参数,剩下的从左至右入栈
      平衡堆栈方式:自身清理堆栈,调用者不用清理堆栈

其中,_fastcall压栈是最快,而且节省内存的一种调用约定(参数不超过2个的时候),而且我们发现,_cdecl这种调用约定和_fastcall是不用我们手动去清理堆栈的。这也就是效率高的原因。

我们知道了WinMian函数需要四个参数,并且其中一个为当前应用程序实例句柄,那么我们就大概知道:在WinMain函数之前,需要获取当前应用程序的实例句柄,我们根据这个,再结合四个参数,就能很容易找到应用程序真正的入口了,而且这个入口离EntryPoint不远:
我们来到OllyDbg中来找一下:

OllyDbg

很明显这里自动断点是EntryPoint,而且是一个call那我们单步一下,看会不会进入这个函数,发现进入了,那我们就需要在这个函数中去找:

我这个程序是进入了,所以我在这个函数中去找:

GetModuleHandleW
进入call,往后翻一下,很快就看到了GetModuleHandleW函数,这个函数功能就是获取当前应用程序实例句柄,那么既然第二个参数找到了,应用程序真正的入口也不远了,这里注意找入口的时候严格是4个参数,结合各种汇编代码确定是4个参数,那么这个函数大概率就是入口函数了:

这里我找到的入口函数:

WinMain

这里是压入了四个参数,而且在这个函数中,OllyDbg自动解析出了很多Kener32的函数,所以我确定这个就是应用程序入口函数。

应用程序入口函数

二.定位回调函数

既然我们找到了应用程序入口函数,那么找回调函数就比较容易了:

我们在注册窗口的时候,需要一个窗口类,而这个窗口类中,就包含了回调函数的地址,那么现在我们主要的任务就是找到注册窗口的函数,在注册窗口函数中,我们只传入了一个参数,就是窗口类的指针,那么我们在找到注册窗口函数后,找到这个指针参数,这个指针的第二个成员,就是回调函数地址了,我们跟进去就是回调函数了。

回调函数
可以看到OllyDbg已经帮我们解析出了注册窗口函数,在这个函数之前,只压入了一个参数(eax)那么eax中存的值,肯定就是这个指针了,我们打开数据窗口,将eax指向的地址输入进去,就可以看到窗口类了:

eax
那么第二个成员,就是回调函数地址了,我们跟进去,就是回调函数了。

回调函数

三.浅析ESP寻址方式

这里的ESP寻址方式和EBP寻址方式差不多,但是这里的ESP中存储的地址,会随时变更,所以要根据ESP寻址方式,必须要单步执行到最近的入栈后查看数据。

四.具体事件的处理定位

在找到了回调函数之后,我们就要找具体的事件是怎样处理的了(点击按钮,点击鼠标,按下键盘等动作)。
我们在定义回调函数的时候,传入了4个参数:

LRESULT CALLBACK WindowProc(
	HWND hWnd,
	UINT uMsg,
	WPARAM wParam,
	LPARAM lParam
);

而我们在做消息处理的时候,我们是根据参数uMsg来区分到底是哪种消息的。而uMsg是第二个参数,使用ESP寻址就是[esp+8],我们直接在回调函数开始的位置下断点即可。
这里如果直接下断点的话,由于Windows消息会很多,所以应用程序会频繁地停在这里,所以我们必须指定条件断点,指定消息,当处理这个消息的时候,断在这里,我们就能清楚地知道,当应用程序收到这个消息的时候,做了哪些处理:

条件断点
这里我指定的是当键盘KEY被按下的时候,程序断在这里:

应用程序断点
好了,掌握了这些,相信大家在逆向程序的时候会如鱼得水。
今天的分享就到这里,如果文章中出现了错误或者是我个人理解不到位的地方,还请大家指出来,我会非常虚心地学习,希望大家共同进步!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Gateway网关详解及实践---SpringCloud组件(五)

Gateway网关详解及实践 一 简介1.1介绍1.2.GateWay核⼼概念1.3.GateWay核心功能 二Gateway入门案例2.1 gateway依赖2.2 gateway配置2.3 gateway测试 三Gateway面向服务的路由3.1.门案例问题3.2.gateway-server结合eureka步骤3.2.1.添加Eureka客户端依赖3.2.2.添加Eureka配置3.2…

MySQL进阶-MySQL体系结构和常见存储引擎的比较

本文介绍MySQL体系结构以及存储引擎(InnoDB、MyISAM、Memory)的比较 文章目录 MySQL 体系结构连接层服务层连接池系统管理和控制工具SQL接口解析器查询优化器缓存 引擎层存储层 存储引擎InnoDBMyISAMMemory区别 MySQL 体系结构 连接层 最上层是一些客户…

Rust 正式发布八周年纪念日 2023.5.15

图源:维基百科 目录 Rust 1. Rust的特点 1.1 安全性 1.2 并发性 1.3 性能 1.4 代码可读性 2. 使用场景 2.1 系统编程 2.2 Web开发 2.3 游戏开发 3. 与其他语言的对比 4. 代码示例 1. Hello, World! 2. 简单的函数 3. 变量绑定和变量类型推断 4. 结…

dayday60-120

目录 60 申论强化361 申论强化462 模考大赛错题63 言语真题164 言语真题65 言语真题366 判断真题1676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 60 申论强化3 1.公文题的格式不允许丢…

Vector - CAPL - CAN消息自动化设置

目录 canGetDataLength -- 获取CAN消息有效负载长度 代码示例 canOutputErrorFrame -- 模拟发送错误帧消息 代码示例 isStdId & isExtId -- 判断报文是标准帧&扩展帧 代码示例 mkExtId -- 将标准帧转换为扩展帧 代码示例 valOfId -- CAN消息的长值标识符 代…

基于SpringBoot的原创歌曲平台的设计与实现

背景 原创歌曲分享平台,为了随时随地查看原创歌曲分享信息提供了便捷的方法,更重要的是大大的简化了管理员管理原创歌曲分享信息的方式方法,更提供了其他想要了解原创歌曲分享信息及运作情况以及挑选方便快捷的可靠渠道。相比于传统原创歌曲…

六级备考33天|CET-SET6|六级口语|备考手册|考试样题|热门话题

目录 样题 1 The benefits of college athletics 2 The adverse impact of cheating on examinations 3 My view on working part-time during ones college years 4 Should students take part in extracurricular activities 5 If you choose overseas studies 6 The…

基于stm32物联网开发板(3)--SYN6288语音模块

基于stm32物联网开发板(3)–SYN6288语音模块 1.SYN6288语音模块展示示例 SYN6288语音模块 2.概述 SYN6288-A语音合成模块是一款性价比更高,效果更自然的一款中高端语音合技术 。 SYN6288-A通过异步串口接收待合成的文本,实现文本到声音(TTS&…

SPL即将取代SQL?

先来看看两者的定义。 SQL:结构化查询语言。 SPL:结构化数据计算语言。 既然是比较文章,那必然是要突出一方的优势。 以下是SQL的痛点以及SPL的优点: 1.SQL缺乏离散性,集合化不彻底;SPL离散与集合充分结…

如何删除 Docker 镜像、容器和卷?

Docker 是一款常用的容器化平台,通过 Docker 可以将应用程序打包成一个独立的容器,方便地在不同的环境中运行。随着 Docker 的广泛使用,删除 Docker 镜像、容器和卷的操作也变得非常重要。在本文中,我们将介绍如何删除 Docker 镜像…

Python消费Kafka与优化

一.背景与问题 之前使用kafka-python库进行消费数据处理业务逻辑,但是没有深入里面的一些细节,导致会遇到一些坑。正常普通我们常见的一个消费者代码:(假设topic的分区数是20个) from kafka import KafkaConsumerbootstrap_servers [localhost:9092] g…

vim命令大全,非常详细,强烈建议收藏!

Vim是一款常用的文本编辑器,具有强大的功能和高度的可定制性。在本文中,我们将详细介绍Vim的常用命令,并提供相关的示例。如果您是初学者或已经熟练使用Vim,这篇文章都能为您提供帮助。 基本命令 以下是一些基本的Vim命令&#x…

一文足矣:Unity行为树

目录 前言 unity行为树简介 一个简单的敌人AI 正文 个人对行为树的理解 有限状态机与行为树 基本框架 BTNode DataBase 行为树入口 行为树的事件GraphEvent 发送事件 监听事件 脚本发送事件 行为树的管理&操作 一、操作单颗树 二、管理所有树 自定义Task任务 …

python字符串的三种定义方式

之前我们讲过 一些字符串的定义 但当时是说 被双引号包裹的就是字符串 其实并不是特别严谨 这个叫双引号的定义方式 也没错 也只有字符串会被双引号包裹 但还有其他的定义方式 这里 还是先说答案 三种定义方式分别是 单引号定义 双引号定义 三引号定义 参考代码如下 #单引定义…

《点云处理算法》——GROR配准

GROR配准方法(实时性挺好) 一、 效果展示二、VS运行2.1 github源码下载2.2 编译运行 三、后续集成 一、 效果展示 二、VS运行 最近和小伙伴交流,他发现一个好用的配准方法,放在这里实现一下 2.1 github源码下载 gror 2.2 编译…

hexo,typecho,wordpress,hugo的官网下载及介绍

Typecho Typecho是一个轻量级的PHP博客系统,它的优点在于易于安装、使用和管理。Typecho使用MySQL数据库来存储文章和评论,同时支持主题和插件的自定义。Typecho适用于个人博客、技术博客等,因为它的易用性和可扩展性较高。 WordPress Word…

分析SpringBoot 底层机制【Tomcat 启动分析+Spring 容器初始化+Tomcat 如何关联Spring 容器之手动实现

分析SpringBoot 底层机制【Tomcat 启动分析Spring 容器初始化Tomcat 如何关联Spring 容器之手动实现 目录 分析SpringBoot 底层机制【Tomcat 启动分析Spring 容器初始化Tomcat 如何关联Spring 容器之手动实现 实现任务阶段1- 创建Tomcat, 并启动 说明: 分析代码实现 修改…

Android源码之Application与Activity创建时机分析

前言 我们知道App进程是由SystemServer启动的Android启动流程 那App对应的Application以及第一个Activity又是如何创建的呢? 源码分析(API 30为例) 我们从ActivityThread.main函数入手; public static void main(String[] args) {...ActivityThread t…

第八章结构型模式—装饰者模式

文章目录 装饰者模式解决的问题概念结构 案例使用装配者进行改进 使用场景JDK源码分析 静态代理和装饰者的区别 结构型模式描述如何将类或对象按某种布局组成更大的结构,有以下两种: 类结构型模式:采用继承机制来组织接口和类。对象结构型模式…

【Linux】volatile | SIGCHLD | 多线程概念

文章目录 1. volatile编译器优化 2.SIGCHLD信号验证SIGCHLD的存在 3. 多线程多线程概念理解概念什么是多线程调度成本低局部性原理 什么叫做进程 1. volatile 在vscode中,创建signal.c文件 故意在while中没有写代码块,让编译器认为在main中,…