day2

2018-08-12  本文已影响95人  zs0zrc

re课程大纲
逆向工程基础(X86/64,ARM,AARCH64各种架构:汇编10分钟入门、calling convention) IDA Pro、HexRay、OllyDBG、GDB工具准备与快速入门 PE/ELF文件格式 Windows逆向:MFC分析、.Net逆向、X64逆向等 Linux逆向:LD_PRELOAD、混淆与反混淆、OLLVM 加壳与脱壳:壳简介、各类手工脱壳方法 反调试技术:去除花指令、反虚拟机、反调试各种trick 常见算法分析与识别 WinDBG和驱动调试:WinDBG、微软符号表、rootkit调试、加载驱动 其他技巧:符号执行、Pintools、恢复符号、识别虚表、编写IDA Processor

tool类型:
今天

image.png

disassembler 反汇编器
tracer 追踪函数调用
debugger 调试器
decompiler 反编译器
emulator 模拟器
symbolic execution符号执行

具体一些软件软件:
比较大型的有IDA,BINARYNINJA ,radare2
debugger: od 、windbg 、gdb

python 反汇编框架:
capstone:一个轻量级的多平台多架构支持的反汇编框架。支持包括ARM,ARM64,MIPS和x86/x64平台
keystone:一个轻量级的多平台多架构支持的汇编框架
CPU emulator 模拟器:unicorn
unicorn连接点击这里

intel process trace 用硬件来做trace
PIN 插桩
panda静态加动态分析, 在github上面的开源项目

要怎么逆向

  1. 先收集信息
    利用string/file/binwalk/IDA etc等工具,收集信息,发现特征字符串,然后通过google或者github搜索,说不定就能找到源码

  2. 定位 关键代码:

一些逆向的小技巧:

  1. regular pattern of code
  1. regular pattern of binary
  1. identify the open source code
  1. Dynamic Analysis
  1. Reverse code block by block

然后大佬还讲了一下代码混淆:
介绍了几种常见的代码混淆

还介绍了一些壳,这就不记录了

讲的大概就这么多


做的第一道逆向题 re0
先动态解密,因为程序一开始先进行了一个for循环,将judge地址附近的内容与'0xc'进行了异或,所以judge函数不能反编译

image.png

就会显示这个东东

image.png

有两种方法解决:
一种是用ida-python 动态解密,将judge解密
另一种是 运行一下程序,然后把它dump下来

这里讲一下第一种:
ida-python 有内置的api函数,通过ida_bytes库的getbytes函数,获取judge地址的182个字节

buf = ida_bytes.get_bytes(0x600B00, 182)

然后与'0xc'异或后,将值填入相应的地址,这里用了patch_bytes函数

s = ""
for i in xrange(0, len(buf)):
    s += chr(0xC ^ ord(buf[i]))
ida_bytes.patch_bytes(0x600B00, s)

这两个函数的定义:

def get_bytes(ea, size, use_dbg = False):
    """
    Return the specified number of bytes of the program

    @param ea: linear address

    @param size: size of buffer in normal 8-bit bytes

    @param use_dbg: if True, use debugger memory, otherwise just the database

    @return: None on failure
             otherwise a string containing the read bytes
    """
    if use_dbg:
        return ida_idd.dbg_read_memory(ea, size)
    else:
        return ida_bytes.get_bytes(ea, size)


def patch_byte(ea, value):
    """
    Change value of a program byte
    If debugger was active then the debugged process memory will be patched too

    @param ea: linear address
    @param value: new value of the byte

    @return: 1 if the database has been modified,
             0 if either the debugger is running and the process' memory
               has value 'value' at address 'ea',
               or the debugger is not running, and the IDB
               has value 'value' at address 'ea already.
    """
    return ida_bytes.patch_byte(ea, value)

所以写个script,然后用ida运行这个scritp就可以查看judge函数了

不过judge函数的尾部点问题,所以看汇编代码找到正确的尾部,然后重新设置一下

image.png

再反编译一下,发现judge函数可以正确显示了,但是函数栈帧有点问题,它变量显示形式有点奇怪,这里先undefine 函数,用快捷键U,再将函数重新分析一遍 ,快捷键为p,就可以看到正常函数变量了


这里只是做了一个简单的异或,然后比较,写个脚本解密一下flag就出来了

flag_enc="fmcd\x7fk7d;V\x60;np"
flag=""
for i in range(len(flag_enc)):
    c=flag_enc[i]
    flag+=chr(ord(c)^i)

print flag

flag为:flag{n1c3_j0b}

第二道 re1
这是一道MFC??? 注册机的题
大佬讲了两种思路:
一种是将比较flag的汇编代码修改成mov,然后调试查看flag
另一种是慢慢动态调试,利用od,在比较flag的地方查看flag值

因为这是一道注册机的题,看着很容易想到MessageBoxA函数,所以通过MessageBoxA函数的调用,来追踪程序流,找到关键函数

因为这在追踪的时候会追踪到一段不能反编译的汇编代码,在这里要通过自己定义函数,找到正确的函数入口,在那个地址create一个function,就可以反编译了

image.png image.png

同时通过观察它的汇编代码可以发现,在cmp命令中,它比较的注册码长度的为0x21
同时进行注册码检验的函数反编译代码如下:可以看出它是明文比较,所以可以通过动态调试,观察堆栈的值来获得正确的注册码

image.png

打开od调试一下,在0x4015e6处下个断点,按f9执行到断点处,输入33个1
然后就停在断点断点处了,然后往下拉下看到检验注册码的函数,在cmp那下个断点

image.png

在cmp那里下个断点,然后单步执行到那后,观察堆栈的情况

image.png

可以看到此时堆栈有flag的第一个字母,通过连续执行这个循环,就可以将flag一位一位的得出来
flag:flag{The-Y3ll0w-turb4ns-Upri$ing}


evr:
这道题无法直接反编译main函数,它的sp指针有问题,可以用alt+k快捷键手动修复指针,错误修改完后,反编译进入main函数
程序要求先输入username,判断是否正确,然后再执行下面的代码,这里可以不逆它,它和flag没有多大的关系
看了下后面的函数,定位flag字符串密文存放的地址



将 flag_enc提取出来
用 ida-python 的get_bytes函数

buf = get_bytes(0x)
print map(ord,buf)
image.png

字符串一共经过四种加密

这里用爆破的方式来获取flag,爆破的话,从0x20开始爆破,因为爆破的是可见字符

flag_enc=[30,  21,   2,  16,  13,  72,  72, 111, 221, 221, 72, 100,  99, 215,  46,  44, 254, 106, 109,  42, 242, 111, 154,  77, 139,  75,  10, 138,  79,  69,  23,  70,  79,  20,  11];

flag=""
for i in range(7):
    flag+=chr(flag_enc[i]^0x76)
for i in range(7):
    for c in range(0x20,0x7f):
        origc=c
        c=c^0x76^0xad
        c=((2*c)&0xff)&0xaa|(0xff&((c&0xaa)>>1))
        if c==flag_enc[7+i]:
            flag+=chr(origc)
            break
for i in range(7):
    for c in range(0x20,0x7f):
        origc=c
        c=c^0x76^0xbe
        c=((4*c)&0xff)&0xcc|(0xff&((c&0xcc)>>2))
        if c==flag_enc[14+i]:
            flag+=chr(origc)
            break

for i in range(7):
    for c in range(0x20,0x7f):
        origc=c
        c=c^0x76^0xef
        c=((16*c)&0xff)&0xf0|(0xff&((c&0xf0)>>4))
        if c==flag_enc[21+i]:
            flag+=chr(origc)
            break
for i in range(7):
    flag+=chr(flag_enc[i+28]^0x76)
print flag

flag为:hctf{>>D55_CH0CK3R_B0o0M!-9193a09b}


re2:
打开程序后它让你输入一个flag字符串,然后判断是否正确,然后打印对错,这里有个较坑的是它对flag加密的函数在main函数中没有,要通过调试找出来
如图:

image.png

加密后的密文是
['a', 'j', 'y', 'g', 'k', 'F', 'm', '.', '\x7f', '_', '~', '-', 'S', 'V', '{', '8', 'm', 'L', 'n']
写个解密脚本就出flag了
脚本

#!/usr/bin/env python
# -*- coding:UTF-8 -*-

flag_enc = "ajygkFm.\x7f_~-SV{8mLn"

flag_enc = list(flag_enc)
flag = flag_enc
flag[18] = chr(ord(flag_enc[18])^0x13)

for i in range(18):
    k = 17 - i
    flag[k] = chr(ord(flag_enc[k])^k)
    if(k%2 ==1):
        flag[k] = chr(ord(flag[k]) + k)
    else:
        flag[k+2] = flag[k] 

flag[0] = 'f'
temp = ""
for i in range(len(flag)):
    temp += flag[i]

print temp

flag:flag{Ho0k_w1th_Fun}


做题学习的姿势:

get_bytes(address,count)从address处读取count个字节的内容
patch_bytes(address,buf),将adress地址处patch成buf的内容

一些IDA常用的快捷键:

ida反编译的一些技巧:

od的常用命令:
F2:给程序下断点(ctrl+:重载exe程序)
F3:载入exe程序
F4:运行到鼠标指示位置
F7:单步进入到call中
F8:单步跳过call(ctrl+:自动逐行运行程序)
F9:运行exe程序(ctrl+:运行到ret处)(ALT+:快速返回程序领空)
Space:空格键,直接修改汇编代码
CTRL+F:命令模式
CTRL+G:跳转到某个地址
CTRL+B:查找二进制字符串

上一篇下一篇

猜你喜欢

热点阅读