首页 > 其他分享 >常见逻辑语句逆向分析

常见逻辑语句逆向分析

时间:2024-10-18 09:10:55浏览次数:1  
标签:语句 逆向 逻辑 mov case switch ebp 跳转

If else 语句逆向分析

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main(int argc, char* argv[]) {

int sum = 0;

for (int i = 0; i <= argc; i++) {

sum += i;

}

return sum;

汇编代码

00401006 mov dword ptr [ebp-8], 0 ;sum=0

{

0040100D mov dword ptr [ebp-4], 0 ;赋初值语句代码块,i=0

}

00401014 jmp short loc_40101F ;跳转到for语句代码块

{

00401016 mov eax, [ebp-4] ;步长语句代码块

00401019 add eax, 1

0040101C mov [ebp-4], eax ;i+=1

}

{

0040101F mov ecx, [ebp-4] ;for语句代码块

00401022 cmp ecx, [ebp+8]

00401025 jg short loc_401032 ;如果i>argc,则跳转到for结束语句块

00401027 mov edx, [ebp-8]

0040102A add edx, [ebp-4]

0040102D mov [ebp-8], edx ;sum+=i}

00401030 jmp short loc_401016 ;跳转到步长语句代码块

00401032 mov eax, [ebp-8] ;for结束语句块

逆向框架总结

赋初值语句代码块

JMP跳转到for语句代码块

{

步长语句代码块

...

}

{

for语句代码块

执行影响标志位的指令

JXX跳转到for结束语句块

...

}

JMP跳转到步长语句代码块

for结束语句块

Switch 语句逆向分析

非线性switch结构(索引表 最大case值与最小case值差值<256)

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main(int argc, char* argv[]) {

int n = 0;

scanf("%d", &n);

switch (n) {

case 1:

printf("n == 1");

break;

case 2:

printf("n == 2");

break;

case 255:

printf("n == 255");

break;

}

return 0;

}

汇编代码:

00401006 mov dword ptr [ebp-8], 0

0040100D lea eax, [ebp-8]

00401010 push eax

00401011 push offset unk_417160

00401016 call sub_401290

0040101B add esp, 8

0040101E mov ecx, [ebp-8]

00401021 mov [ebp-4], ecx

00401024 mov edx, [ebp-4]

00401027 sub edx, 1

0040102A mov [ebp-4], edx

0040102D cmp dword ptr [ebp-4], 0FEh ; switch 255 cases

00401034 ja short loc_40109F ; jumptable 00401040 default case

00401036 mov eax, [ebp-4]

00401039 movzx ecx, ds:byte_4010C4[eax]

00401040 jmp ds:off_4010A8[ecx*4] ; switch jump

00401047 push offset aN1 ; jumptable 00401040 case 0

0040104C call sub_401250

00401051 add esp, 4

00401054 jmp short loc_40109F ; jumptable 00401040 default case

00401056 push offset aN2 ; jumptable 00401040 case 1

0040105B call sub_401250

00401060 add esp, 4

00401063 jmp short loc_40109F ; jumptable 00401040 default case

00401065 push offset aN3 ; jumptable 00401040 case 2

0040106A call sub_401250

0040106F add esp, 4

00401090 jmp short loc_40109F ; jumptable 00401040 default case

00401092 push offset aN255 ; jumptable 00401040 case 254

00401097 call sub_401250

0040109C add esp, 4

0040109F xor eax, eax ; jumptable 00401040 default case

非线性索引优化: 如果两个case值间隔较大,仍然使用switch的结尾地址或default地址代替地址表中缺少的case地址,这样则会造成极大的空间浪费。非线性的switch结构,可采用制作索引表的方式进行优化。

两张表:case语句块地址表和case语句块索引表。地址表中的每一项保存一个case语句块的首地址,有几个case语句块就有几项。default语句块也在其中,如果没有则保存一个switch结束地址。这个结束地址在地址表中只会保存一份。索引表中会保存地址表的编号,索引表的大小等于最大case值和最小case值的差。

总内存大小:

(MAX-MIN)* 1字节 = 索引表大小

SUM * 4字节 = 地址表大小

占用总字节数 =((MAX-MIN)* 1字节)+(SUM * 4字节)

逆向总结:

mov reg, mem ; 取出switch变量

sub reg,1 ; 调整对齐到索引表的下标0

mov mem, reg

; 影响标记位的指令

jxx xxxx ; 超出范围跳转到switch结尾或 default

mov reg, [mem] ; 取出switch变量

; eax不是必须使用的,但之后的数组查询用到的寄存器一定是此处使用到的寄存器

xor eax,eax

mov al,byte ptr (xxxx)[reg] ; 查询索引表,得到地址表的下标

jmp dword ptr [eax*4+xxxx] ; 查询地址表,得到对应的case块的首地址

有两次查找地址表的过程,先分析第一次查表代码,byte ptr指明了表中的元素类型为byte。然后分析是否使用在第一次查表中获取的单字节数据作为下标,从而决定是否使用相对比例因子的寻址方式进行第二次查表。最后检查基址是否指向了地址表

非线性switch结构(判定树 最大case值与最小case值差值>255)

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main(int argc, char* argv[]) {

int n = 0;

scanf("%d", &n);

switch (n) {

case 2:

printf("n == 2\n");

break;

case 10:

printf("n == 10\n");

break; case 35:

printf("n == 35\n");

break;

case 666:

printf("n == 666\n");

break;

default:

printf("default\n");

break;

}

return 0;

}

汇编代码:

00401006 mov dword ptr [ebp-8], 0

0040100D lea eax, [ebp-8]

00401010 push eax

00401011 push offset unk_417160

00401016 call sub_4011A0

0040101B add esp, 8

0040101E mov ecx, [ebp-8]

00401021 mov [ebp-4], ecx

00401024 cmp dword ptr [ebp-4], 0Ah

00401028 jg short loc_401047 ;如果n>10,则跳转到判断n>10代码块

0040102A cmp dword ptr [ebp-4], 0Ah

0040102E jz short loc_40108B ;如果n==10,则跳转case10语句代码块

00401030 cmp dword ptr [ebp-4], 2

00401034 jz short loc_40105E ;如果n==2,则跳转case2语句代码块

00401042 jmp loc_4010C7 ;跳转default代码块

00401047 cmp dword ptr [ebp-4], 23h

0040104B jz short loc_40109A ;如果n==35,则跳转case35语句代码块

00401053 cmp dword ptr [ebp-4], 29Ah

0040105A jz short loc_4010B8 ;如果n==666,则跳转case666语句代码块

0040105C jmp short loc_4010C7 ;跳转default代码块

总结:

采用多个比较和jcc跳转指令

采用case地址表,直接通过该表首地址+偏移跳转到对应的地址

采用case地址表的同时,也使用偏移表,两表共同作用来找到地址

当switch语句中的case数量≤3或case中的最大数值和最小数值相差≥6时,两种语句的效率几乎相同

其它情况下一般为switch语句的效率更高

当switch语句有序且连续且case数量>3时,其运行的效率最高,也解释了开发过程中为什么要使用连续的case

标签:语句,逆向,逻辑,mov,case,switch,ebp,跳转
From: https://www.cnblogs.com/maqun/p/18473462

相关文章

  • ollydbg逆向基础
    实验目的理解编译过程和调试信息,了解debug模式和release模式的exe进行逆向分析的过程。尝试多种方法找到main函数。实验环境系统:Windows11软件:VS、ollydbg实验代码#include<stdio.h>intmain(){ printf("hellomaqun"); return0;}实验过程查找代码字符在debug文件夹拖拽ex......
  • C语句和程序流
    1.C语言表达式和语句在C中,表达式代表值,而语句代表给计算机的指令。表达式表达式由运算符和操作数组成。最简单的表达式只是一个不带运算符的常量或者变量,例如12或者num。复杂一些的例子是20+30和a=12。语句语句是对计算机的命令。任何以分号结尾的表达式都是一个语句,它不一定......
  • 3:Oracle体系结构(逻辑结构)
    3:Oracle体系结构(逻辑结构) ......
  • SQL语句——日期题目总结
    第一题:查询本周考试的学生成绩。 DATA_ADD()语法:date就是要操作的日期,INTERVAL就是要间隔的日期expr可以写数字,unit用来写单位,比如DATE_ADD(CURDATE(),INTERVAL7DAY)就是当前日期加上一星期。CURDATE()就是当前日期,格式:DATE_ADD(date,INTERVALexprunit)代码解释:就......
  • 机器学习面试笔试知识点-线性回归、逻辑回归(Logistics Regression)和支持向量机(SVM)
    机器学习面试笔试知识点-线性回归、逻辑回归LogisticsRegression和支持向量机SVM一、线性回归1.线性回归的假设函数2.线性回归的损失函数(LossFunction)两者区别3.简述岭回归与Lasso回归以及使用场景4.什么场景下用L1、L2正则化5.什么是ElasticNet回归6.ElasticNet回归......
  • MySql和简单的sql语句
    安装数据库今天进行mysql的安装学习了简单sql语句mysql去官网安装mysql的社区版的八点几版本,安装之后需要设置密码,执行mysql-uroot-p,输入密码就可以进入mysql,使用exit;退出SQL语句分为DDL,DML,DQL,DCL,几大类,creatbasedata......
  • yield 语句 - 提供下一个元素
    yield语句-提供下一个元素项目2024/10/153个参与者反馈本文内容迭代器的执行C#语言规范另请参阅在迭代器中使用 yield 语句提供下一个值或表示迭代结束。 yield 语句有以下两种形式:yieldreturn:在迭代中提供下一个值,如以下示例所示:C#复制 运行f......
  • goto语句的风险
    在编程中,goto语句会使程序控制流跳转到指定的标签位置。尽管它在某些情况下可以简化代码(例如在错误处理或异常情况下快速退出多个嵌套的循环),但通常建议慎用甚至避免使用goto语句。主要原因如下:1. 破坏代码的结构化goto语句允许程序跳转到代码中的任意位置,从而打破了程序的结构......
  • C#中判断的应用说明二(switch语句)
    一.判断的定义说明判断结构要求程序员指定一个或多个要评估或测试的条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的)。下面是大多数编程语言中典型的判断结构的一般形式:二.判断语句C#提供了以下类型的判断语句,查看每个语句的细节。语句描述switch语......
  • 如何避免日志中打印SQL语句:完整解决方案
    个人名片......