花指令基础

花指令基础

偶尔更新。。。

默认会一点cpp和汇编。

1. 简介

花指令可以误导反汇编,但不影响程序正常执行(运行时花指令位于不可执行的代码路径)。

反汇编算法主要可以分为两类:递归下降算法和线性扫描算法。

线性扫描算法扫描整个数据段,对每条指令进行反汇编,无法区分数据与代码,导致代码段的数据误解释为指令。

递归下降法强调控制流的概念,控制流根据一条指令是否被另一条指令引用来决定是否对其进行反汇编,遇到非控制转移指令时顺序进行反汇编,而遇到控制转移指令时则从转移地址处开始进行反汇编。

call机器码0E8h

nop机器码90h

retn先进行esp加n操作,而ret没有此项操作

先来个简单例子

visual studio 2022编译一下,exe用ida打开

#include<iostream>
using namespace std;
int main() {
    int x;
    _asm {//vc内联汇编插入花指令
        jz label;
        jnz label;
        _emit 0xE8;//立即数_emit:表示在这插入一个数据
    label:
    }
    cin>>x;
    cout<<x;
    system("pause");
    return 0;
}

main函数一个明显的JUMPOUT,应当是有花指令

在这里插入图片描述

在这里插入图片描述

按U,然后把E8 patch成90 ,再按C转成code

在这里插入图片描述

在开头按p,再按F5,反汇编成功

在这里插入图片描述

2. 常见类型

1. jx+jnx

jnz和jz的互补跳转

_asm{
    jz Label;
    jnz Label;
    _emit 0xC7;//这行patch成90,然后按C
    Label:
}

跳转指令构造花指令

 __asm {
         push ebx;
         xor ebx, ebx;
         test ebx, ebx;//zf为1,执行jz
         jnz LABEL7;
         jz    LABEL8;//永真条件跳转
     LABEL7:
         _emit 0xC7;//显示为db,影响反汇编(p和F5失效)
     		//上面这行patch成90,然后按C
     LABEL8:
         pop ebx;
     }

2. call+add [esp]+ret

call与ret构造花指令

__asm {
         call LABEL9;//下一条"指令" db 0x83地址压栈
         _emit 0x83;
     LABEL9:
         add dword ptr ss : [esp] , 8;//这行改了esp指向的栈顶数据
    		//003D186A+8=003D1872
         ret;//但是ret从栈顶拿出数据给eip,所以能正常到mov esi,esp处运行
         __emit 0xF3;
     }

在这里插入图片描述

如下图,在爆红那一行按U,把83h patch掉,
在这里插入图片描述

然后看 0F3,8B,0F4 ->rep mov esi, esp,前面没有操作ecx寄存器,估计F3是花指令,patch掉。
在这里插入图片描述

然后成功报错,Options-General-Disassembly-Stack pointer,打开堆栈指针,没看出什么东西

把36h到C3h那一段全nop掉就行,然后在main开头按U,C,P,F5。

3. 等价解析

1. push pop

push 0x1111
在x86等价于
sub esp,0x4;
mov [esp],0x11111;

pop eax;
在x86程序里面就等价于
mov eax,[esp];
add esp,0x4;
//可以用多个pop代替add esp,0x4

2. jmp call retn

jmp addr
相当于
mov eip,addr

call addr
相当于
push next opcodeAddr; 一般4字节
jmp addr

call 0h
16进制为:E8 00 00 00 00
用于获取下一行地址,也可获取EIP的值

retn 0x5;
相当于
mov eip,[esp]
add esp,0x4+0x5

3. enter leave

enter 8,0
相当于
push ebp;
mov ebp,esp;
sub esp,8;

leave
相当于
mov esp, ebp;
pop ebp;

4. and

常用来栈对齐

16位对齐
and esp,0xfffffff0

MoeCTF 2022 chicken_soup

ida打开,找到main函数

在这里插入图片描述

loc_401000和loc_401080加了花指令,两处E9改成90

unsigned int __cdecl sub_401000(const char *a1)
{
  unsigned int result; // eax
  unsigned int i; // [esp+18h] [ebp-8h]

  for ( i = 0; ; ++i )
  {
    result = strlen(a1) - 1;
    if ( i >= result )
      break;
    a1[i] += a1[i + 1];
  }
  return result;
}
unsigned int __cdecl sub_401080(const char *a1)
{
  unsigned int result; // eax
  unsigned int i; // [esp+18h] [ebp-8h]

  for ( i = 0; ; ++i )
  {
    result = i;
    if ( i >= strlen(a1) )
      break;
    a1[i] = (16 * a1[i]) | ((int)(unsigned __int8)a1[i] >> 4);
  }
  return result;
}

sub_401110是个字符串比较函数

易得

c=[0xCD, 0x4D, 0x8C, 0x7D, 0xAD, 0x1E, 0xBE, 0x4A, 0x8A, 0x7D, 0xBC, 0x7C, 0xFC, 0x2E, 0x2A, 0x79, 0x9D, 0x6A, 0x1A, 0xCC, 0x3D, 0x4A, 0xF8, 0x3C, 0x79, 0x69, 0x39, 0xD9, 0xDD, 0x9D, 0xA9, 0x69, 0x4C, 0x8C, 0xDD, 0x59, 0xE9, 0xD7]
for i in range(len(c)):
    c[i] = (  c[i]//16) | (c[i] << 4)&0xFF;#实际是交换高4位与低4位
for i in range(len(c)-2,-1,-1):
    c[i]-=c[i+1]
print(bytes(c))
#moectf{p4tch_pr0gr4m_t0_d3c0mpi1e_it!}

参考

  1. CTF逆向Reverse 花指令介绍 and NSSCTF靶场入门题目复现 znonono

  2. 逆向专辑–花指令阅读与分析 ZhaoWu

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值