IDA使用入门

Author Avatar
Aryb1n 8月 12, 2017

基本使用

主要是记下一些快捷键?

  1. IDA View
    空格可以切换Graph视图和正常视图
    Graph其实很少用,所以可以在
    Options - General - Graph里可以把use graph view by default勾掉
  1. 交叉引用
    some asm code   ; CODE XREF: some location
    some asm code   ; DATA XREF: some location
    
  • 代码交叉引用
  • 数据交叉引用
  1. Hex View
    有的时候是问号, 表示IDA无法识别给定虚拟地址范围内的值
    如果包含bss的话, 就会这样子…

明天早起继续看

  1. 跳转
    G 跳转到…
    Esc 后退

  2. 重命名
    N

  3. 举了一个cdecl不需要清理参数的例子
    正常情况

    ; demo_call(1, 2, 3, 4)
    push 4
    push 3
    push 2
    push 1
    call demo_call
    add  esp, 16    ; 调用者清理参数
    

有的时候, 没有采用push的方法

; demo_call(1, 2, 3, 4)
mov [esp+12], 4
mov [esp+8], 3
mov [esp+4], 2
mov [esp], 1
call demo_call
; 不需要调用方清理参数
  1. 搜索
    ALT + T 文本搜索
    ALT + B 二进制搜索

  2. 代码数据互换
    U(undefine) 取消定义 code变成原始一个一个byte

C(code) data -> code
D(data) code -> data 在数据转盘里切换data种类

数据转盘里设置 options -> Steup data types

  1. 数据相关
    db 1字节 byte
    dw 2字节 word
    dd 4字节 dword
    dq 8字节 qword

  2. 数组
    选中数据开头, Edit -> Array,可以创建数组
    这样子关于数组的访问就是基于Array_head + offset的形式
    后来又遇到了问题…我的数组每个元素多大…怎么在建立数组菜单里没法选择
    然后发现是需要先把数据开头第一个元素变成想要的类型, 比如word
    然后再新建数组, 得到的就是数组元素大小就是和第一个元素一样的

  1. 结构体
    结构体, 几乎没法直接分辨是用了结构体
    要自己手动识别, 然后添加
    一般一个变量(加不同间隔)偏移量的..这个变量可能就是某种类型的
    特别是看到有的时候会把什么函数指针啊, 之类的赋值给他的成员
    基本就是个类or结构体了

在建立结构体的时候要注意那个, emmmmm, 注意在结构体末尾那一行点新建元素…不是开头那一行, 具体是怎么的来着…忘记了, 算了, 2333333

C++

C++ 果然复杂的…毛线一样

  1. this
    所有非静态C++成员函数都是用this指针
    把this看做是传递到所有非静态成员函数的第一个隐含参数
    MS VC++ 遵循thiscall, 把this传入到ECX寄存器
    GUN g++ 把this看成最左边的参数,最后压入栈

  2. 虚函数 虚表
    包含虚函数的类的第一个数据成员是一个指针,叫做虚表指针(vtable pointer), 指向他的虚表
    虚表是一个包含类中指向每一个虚函数的指针的表

class BaseCalss {
    public: 
        BaseClass();
        virtual void vfunc1() = 0;
        virtual void vfunc2();
        virtual void vfunc3();
        virtual void vfunc4();
    private:
        int x, y;
};

class SubClass: public BaseCalss {
    public: 
        SubClass();
        virtual void vfunc1();
        virtual void vfunc3();
        virtual void vfunc5();
    private:
        int z;
};

BaseClass含有 4个虚函数 + 3个数据成员(vtable pointer, x, y)
SubClass含有 5个虚函数 + 4个数据成员(vtable pointer, x, y, z)

我照着抄写的例子怎么通不过…好气啊…

vtable是放在rodata段的…那么就不能hack了是吗…
emmm,好像不需要hack这个表…我们的hack点在于把对象中指向vtable的指针的指向改变…

其实不太懂,我这里个g++涉及到类, 比如 new, 和对象成员函数调用都是用了fastcall

而且这一块的汇编..惨不忍睹…
我还是太菜了

RTTI(Runtime Type Identification)

运行时类型识别

HITCON Training Lab15

就是一个关于类的pwn…C++的逆向还是太….
看着太累了

Patch

上次做题目,patch是使劲点patch,结果发现没毛用
后来在IDA里记下offset, 然后用GHex修改的…

今天翻开书…看到这样子一段话

IDA并不能帮助你轻松修改二进制文件, …, 一些顽固的用户通常会继续提出以下问题:”那么Edit > Patch Program有什么用”

哈哈哈哈, 不过, 到底是我wine的锅, 还是确实不能用这个功能
好像又可以了…

IDA脚本

  1. File > Script
  2. File > IDC Command
  3. File > Python Command

这一块没怎么学..略过了

反静态分析

例子1

start_:
    xor eax, eax
    test eax, eax
    jz label1
    jnz label1
    db 0E8H ; call

label1:
    xor eax, 3
    add eax, 4
    ret

看这里的db 0E8H就是junk code, 这里其实不会被执行到, 但对他编译, 再反汇编之后…会起到混淆作用

xor eax, eax
test eax, eax
je xxxxxx
jne xxxxxx
call yyyyyyy ; 看这里这个junk code

这个时候需要把call yyyyyy这里Unfined, 按一下U
然后再在要跳转到的xxxxxx这个位置Code, 即按一下C
emmmmmmmm, 这样子

例子2
反汇编代码(修复后)

    call loc_A04B0D7
    db   0C7h   ; 0x0A04B0D6
loc_A04B0D7:
    pop eax     ; (eax) = 0x0A04B0D6
    lea eax, [eax + 0Ah]    ; (eax) = 0x0A04B0E0
    db   0E8h
    jmp eax
start endp

这里的call是个假的…
就是把返回地址ret给pop出去了, 然后若无其事的继续执行
后来的这个jmp eaxeax的值实际上是能确定的, 但IDA不能识别

这里需要修复两次一个是db 0C7h, 一个是db 0E8h

先根据call loc_A04B0D7
找到loca_A04B0DB这里重新反汇编一下
然后在db 0E8h这里原来是

loc_A04B0DB:
    jmp short near ptr loc_A04B0DB + 1  ; E8 FF
start endp
db 0E0h                                 ; E0

其实应该是

db 0E8h     ; E8
jmp eax     ; FF E0
start endp

例子3 动态计算目标地址

... ;寄存器之间各种计算
pop eax
pop ebx
... ;恢复现场
xchg edi, [esp]
retn

返回地址是动态计算出来,存到了edi里, 之后存到了栈顶[esp]

  1. 加壳…
    加了壳, 尤其是UPX这样子的壳, 没办法静态分析了就
    就要先脱壳

加壳后的特征:

1. 有非标准段名称
1. 一个或者多个程序既可以写又可以执行
1. Functions, Imports, Strins 很少有内容
  1. 一般壳用到的API (windows…)

    HINSTANCE LoadLibrary(LPCTSTR lpLibFileName)    // 根据名称加载dll, 返回句柄
    HMODULE   GetModuleHandle(LPCTSTR lpModuleName)  // 获取dll句柄
    FARPROC   GetProcAddress(
             HMODULE hModule,    // DLL模块句柄
             LPCSTR  lpProcName  // 函数名
             )
    

    先把dll加载进来, 最后获取函数
    一般的,可能dll早已经加载进来, 那么直接获取句柄, 然后获取函数就可以了

  2. 有目的的攻击分析工具
    woc, 这个厉害了…

反动态分析

  1. 检测是在虚拟机运行还是本机运行
  2. 检测检查工具
  3. 检测调试器(反调试)
  • isDebuggerPresent (win)
  • ptrace (Linux)
    这一块收藏过一篇文章, 然后再看一下

自己学习一丢丢C++

c++感觉会push好多东西.导致IDA里看到某些函数参数错误

就比如我这里的cout << 2 << 3
转化得到的其实是cout << 2cout << 3
所以

sub  esp, 8
push 2
push offset _ZSt4cout@@GLIBCXX_3_4
call __ZNSolsEi
add  esp, 10h

sub  esp, 8
push 3
push offset _ZSt4cout@@GLIBCXX_3_4
call __ZNSolsEi
add  esp, 10h

我其实不太明白…为什么
这里是两个参数,只要

push 2
push offset _ZSt4cout@@GLIBCXX_3_4
call __ZNSolsEi
add  esp, 8

这样子直接
push 8字节参数, 调用函数, add esp, 8就可以了,

为什么要先sub esp, 8, 然后压参, 调用, 最后算上清理参数的8个字节, 清理的时候就是add esp, 10h
为什么呢 ==!啊啊啊

这个只有输入输出其实还不太复杂
这个string…好复杂啊…
就这一小节

int main() {
    string s = "123";
    string ss = "456";
    cin >> s;
    cout << s;
    cout << 2;
    return 0;
}

大概流程是

..
call std::allocator::allocator(void)
call 各种命名空间::basic_string()   ;初始化s
call std::allocator::~allocator(void)

call std::allocator::allocator(void)
call 各种命名空间::basic_string()   ;初始化ss
call std::allocator::~allocator(void)

call >>(offset_cin, )

call <<(offset_cout, )

call <<(offset_cout, 2)

call 各种命名空间::~basic_string()   ;销毁s
call 各种命名空间::~basic_string()   ;销毁ss

F5的问题

第一次要在那个, emmmmm, 要在IDA View窗口 的 图表模式按下F5, 才能起作用
如果已经用空格切换到文字模式, 好像按下F5没用…

defs.h

我们提取出来的IDA里的c代码, 如果直接编译是通不过的,因为是某些东西未定义

这个文件,,emmmm,很有用,在IDA的plugins目录下

This file contains definitions used by the Hex-Rays decompiler output.

比如我们提取出IDA里的某一块逻辑出来, 这个时候会有一些比如DOWRD之类类型的定义, 这些定义都在这个头文件里,

数据类型

今天想要…把数据变成负数的时候…一时不知道怎么办
然后发现要先变成10进制, 然后右键选单里才有变成负数…
右键的时候稍微靠后一点…离的太近可能出不来