从零开始的程序逆向之路基础篇 第二章——用OllyDbg(OD)分析一个简单的软件
作者:Crazyman_Army
原文来自:https://bbs.ichunqiu.com/thread-43469-1-1.html
0x00知识回顾 (由于笔者省事,没开XP虚拟机,而且没关闭ASLR,所以每次重载的内存地址会不一样)
在第一章的内容中,笔者已经讲了OllyDbg(简称OD)的界面介绍以及基础的操作,普及了常用的汇编指令
上次课在底下的附件中,我留下了一个演示样例,大家载入OD后搜索到字符串点击跟踪到反汇编窗口的时候会发现与第一章所讲的程序的框架不太一样.
尤其可见多出了很多的call指令,call指令在汇编中就是调用子程序,下面放出代码,各位同学可以比对一下与上篇文件所贴出代码的不同
代码如下:
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
BOOL getProcess(const char *procressName);
BOOL getProcess(const char *procressName)
{
char pName[MAX_PATH];
strcpy(pName, procressName);
CharLowerBuff(pName, MAX_PATH);
PROCESSENTRY32 currentProcess;
currentProcess.dwSize = sizeof(currentProcess);
HANDLE hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcess == INVALID_HANDLE_VALUE)
{
printf("CreateToolhelp32Snapshot()调用失败!\n");
return FALSE;
}
_asm NOP;
BOOL bMore = Process32First(hProcess, ¤tProcess);
while (bMore)
{
CharLowerBuff(currentProcess.szExeFile, MAX_PATH);
if (strcmp(currentProcess.szExeFile, pName) == 0)
{
CloseHandle(hProcess);
return TRUE;
}
bMore = Process32Next(hProcess, ¤tProcess);
}
CloseHandle(hProcess);
return FALSE;
}
int main()
{
char* process = "explorer.exe";
if (getProcess(process))
{
printf("发现explorer.exe\n");
system("pause");
exit(0);
}
else
{
printf("没有发现explorer.exe\n");
printf("Cracke Success!");
}
getchar();
return 0;
}
从代码角度来看,很明显,这次笔者讲判断进程封装成一个返回布尔值的函数,所以才会在核心判断部分出现如此多的调用,那这当然不能像上次一样改一步简单的跳转就解决问题,如果改得不对就会造成程序的崩溃。
下面笔者通过三种方法来绕过这个检验explorer.exe进程的小程序
方法一:修改判断进程的变量名称
在只能搜索中,我们看到了explorer.exe这个进程的字符串,我们用鼠标选中后,双击,在反汇编窗口中跟随
反汇编窗口显示的如下:
用鼠标选中这条代码右键 -> 数据窗口中跟随–> 内存地址
数据窗口随之发生了变化,在数据窗口上选中一部分数据右键
右键 –> 复制到可执行文件
点击放大键放大该窗口
然后就可以胡乱修改explorer.exe这个字符串
笔者这里就随便修改了
修改如下:
在窗口上右键,保存文件
文件保存成功
点击运行
第一种方法破解成功
方法二:确认过眼神,你不是我们的人
回到判断的核心代码,这里面是jnz来进行进程的判断
那jnz 的全拼写是 jump not zero 那其的反义词即为 jump
Zero,即为jz 或者 je (jump equal),那这样原来的判断explorer.exe就改为了不判断explorer.exe,这样就绕过了检测进程.
下面我们来实际操作,用鼠标选中后
双击
将jnz short 00291158改为 jz short 00291158或者 je short 00291158,将使用nop填充勾掉
点击汇编
然后再保存文件,保存后运行
第二种破解方法成功
方法三:条件改强制
如下图,这个jnz short 00101158是如果zf=0时就会跳转
而jnz所在代码的地址为00101137,我们尝试让其无条件跳转到00101137下面一个地址,也就是00101139(下图红框锁标注的区域)
双击地址为00101137的那条代码,如下图所示 将jnz short 00101158改为jmp short 00101139,点击汇编
点击运行按钮
程序运行截图:
很显然破解成功了,那具体是怎么个原理呢,我们这里留个悬念,等用od能分析一个简单程序后,我们回过头来解释这个问题
00x01 用OllyDbg分析一个简单的程序
下面,笔者将带领同学去用OllyDbg来分析一个简单的程序
笔者为了方便写了一个简单的判断输入数字的程序,代码如下:
载入OD
反汇编窗口上右键中文搜搜引擎 -> 智能搜索
跟踪后的代码可以看到:
在有程序保护的情况下,你可能无法搜索到字符串,这里先不讨论,笔者将带领同学一步一步分析这个简单的程序
这里面push ebp movebp,esp push ecx可以简单的理解为源码中的int main()后的{ (这里为了方便于理解)
push Text.013E3E34,push的意思自然是压栈
这里就不得不要说说C语言中的printf
下面是printf的函数声明
int printf(const char *format, ...);
那在默认的情况下,printf函数应该有一个const char*型的参数,而这一行就是把“Please Input Flag Number:”这个字符串指针当成参数1,压入栈中
mov [local.1],0x0
那究竟这个[local.1]是何方神圣呢?
我们选中这段代码
右键 -> 分析 –> 从模块中删除分析
此时[local.1]就露出了他真面目[ebp-4]
第一章的时候我们讲到了,mov(move)数据传送指令
mov a,b 把b的值传给a
当然mov也可以对内存中的数据进行赋值
这里面 mov [ebp-4],0x0 就是把0赋值给内存中所设置的变量,其中[]操作符可以引用内存中的数据
类似于源码中
call指令就是调用,那就是调用printf函数输出”PleaseInput Flag Number”这个字符串指针
lea eax,dword ptrss:[ebp-0x4]
LEA指令是一个计算机指令,可以将有效地址传送到指定的的寄存器。
按道理来说就把变量1的地址传递给了eax寄存器
push eax
push Text.00EE3E50
现在的eax其实被传递了变量1的地址
往下面一瞥会发现scanf函数
下面是scanf函数的定义
int scanf(const char * restrict format,...);
一般代码中都是scanf(“格式说明符”,&变量地址)
这里面格式说明符是函数的参数1,变量地址是函数的参数2
而这个变量地址就类似于图中的push eax-> 参数2
而格式说明符就类似于图中的pushText.00EE3E50 ->参数1
那为何是先把参数2推入,再把参数1推入呢?
比如 int Text(a,b,c)这个函数Text参数为a,b,c
在Windows调用规定中
这个函数在汇编中会
Push c
Push b
Push a
Call Text函数的地址
在此你应该能发现参数啊a,b,c却被反向以c,b,a的顺序压入栈中,然后再callText函数的地址
Call指令当然就是调用scanf函数读取输入flag的值
Add esp,0xc
由于_cdcel调用约定,故需要进行堆栈平衡
cmp dword ptrss:[ebp-0x4],0x2F59
cmp是比较指令 而这里面比较的两个对象是变量1与0x2F9(12121)
故cmp指令可以影响标志寄存器
Jnz short Text.009E1036
Jnz跳转指令,由于前面的cmp指令
若变量1-12121=0 Z位=1 jnz不跳转
若变量1-12121!=0 Z位=0 jnz跳转到009E1036
那这个程序的大致流程就是输入变量1的数以后与12121做比较,如果两个数相等,Z位=1 ,jnz不跳转,输入Right!;如果两个数不相等,Z位=0,jnz跳转到009E1036上,输出Error!
然后剩下的代码分析和前面所讲的差不多,大家可以自己写一下注释
00x02总结
本篇我们介绍如何用OD来分析一个简单的程序,同学可以在事后自己用OD跑一下,这样会理解的更加深刻
下一章 如何用OD(OllyDbg)动态调试程序
点击“阅读原文”即可下载本次文章所用到的几个程序的例子哦~
从零开始的程序逆向之路基础篇 第二章——用OllyDbg(OD)分析一个简单的软件的更多相关文章
- 顶级c程序员之路 基础篇 - 第一章 关键字的深度理解 number-1
c语言有32个关键字,每个关键字你都理解吗? 今天出场的是: auto , register, static, extern 为什么他们会一起呢,说到这里不得不谈到c语言对变量的描述. c给每 ...
- Java语言程序设计(基础篇)第二章
第二章 基本程序设计 2.2 编写简单的程序 1.变量名尽量选择描述性的名字(descriptive name). 2.实数(即带小数点的数字)在计算机中使用一种浮点的方法来表示.因此,实数也称为浮点 ...
- 从零开始的程序逆向之路 第一章——认识OD(Ollydbg)以及常用汇编扫盲
作者:Crazyman_Army 原文来自:https://bbs.ichunqiu.com/thread-43041-1-1.html 0×00 序言: 1.自从上次笔者调戏完盗取文件密码大黑客后, ...
- Java编程基础篇第二章
关键字 概述:被Java语言赋予特定含义的单词. 特点:组成关键字的字母全部为小写字母. 标识符 概述:给类,接口,包,方法,常量起名字时的字符序列 组成规则:英文大小写字母,数字,$和— 命名规则. ...
- 编写高质量代码:改善Java程序的151个建议(第二章:基本类型)
编写高质量代码:改善Java程序的151个建议(第二章:基本类型) 目录 建议21:用偶判断,不用奇判断 建议22:用整数类型处理货币 建议23:不要让类型默默转换 建议24:边界还是边界 建议25: ...
- ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局
本文转自 :http://www.cnblogs.com/wendingding/p/3761730.html ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布 ...
- iOS开发UI篇—使用picker View控件完成一个简单的选餐应用
iOS开发UI篇—使用picker View控件完成一个简单的选餐应用 一.实现效果 说明:点击随机按钮,能够自动选取,下方数据自动刷新. 二.实现思路 1.picker view的有默认高度为162 ...
- python之路基础篇
基础篇 1.Python基础之初识python 2.Python数据类型之字符串 3.Python数据类型之列表 4.Python数据类型之元祖 5.Python数据类型之字典 6.Python Se ...
- python学习之路基础篇(第四篇)
一.课程内容回顾 1.python基础 2.基本数据类型 (str|list|dict|tuple) 3.将字符串“老男人”转换成utf-8 s = "老男人" ret = by ...
随机推荐
- js方法用来获取路径传参上所带的参数
//js方法用来获取路径传参上所带的参数 function GetQueryString(param) { var reg = new RegExp("(^|&)" + p ...
- SQL 读取csv 文件批量插入数据
use test /* create table temp_pre ( vc_product_id varchar(20) default '', en_in_amount numeric(9,2)d ...
- JAVA数据库连接池C3p0 以及阿里Druid提供的连接池
一:连接池的定义 本质上就是个容器(集合) 存放数据库连接的容器,当系统初始化后,容器被创建,容器中就会申请一些连接对象,当用户来访问数据库的时候,从容器中取连接对象,用户用完之后,归还. 二:常用的 ...
- Python设计模式 - UML - 部署图(Deployment Diagram)
简介 部署图也称配置图,用来显示系统中硬件和软件的物理架构.从中可以了解到软件和硬件组件之间的物理拓扑.连接关系以及处理节点的分布情况. 部署图建模步骤 - 找出需要进行部署的各类节点,如网络硬件设备 ...
- [leetcode]200. Number of Islands岛屿个数
Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surro ...
- 震惊!90%的程序员不知道的Java知识!
震惊!90%的程序员不知道的Java知识! 初学Java的时候都会接触的代码 public static void main(String[] args){ ... } 当时就像背公式一样把这行代码给 ...
- Python开发——数据类型【字典】
字典的定义 # Python语言中唯一的类型映射 # 键与值之间用“:”分开 # 项与项之间用“,”分开 person = {"name":"yuan",&qu ...
- 33.MySQL高可用架构
33.高可用架构33.1 MMM架构MMM(Master-Master replication manager for MySQL)是一套支持双主故障切换和双主日常管理的脚本程序(Perl).主要用来 ...
- ORM常用字段介绍
Django中的ORM Django项目使用MySQL数据库 1. 在Django项目的settings.py文件中,配置数据库连接信息: DATABASES = { "default&qu ...
- 代码之髓读后感——语法&流程&函数&错误处理
title: 代码之髓读后感2.md date: 2017-07-08 17:33:11 categories: tags: Perl的设计者:Larry Wall在<Programming P ...