IDA使用入门
基本使用
主要是记下一些快捷键?
- IDA View
空格可以切换Graph视图和正常视图
Graph其实很少用,所以可以在
Options - General - Graph里可以把use graph view by default
勾掉
- 交叉引用
some asm code ; CODE XREF: some location some asm code ; DATA XREF: some location
- 代码交叉引用
- 数据交叉引用
- Hex View
有的时候是问号, 表示IDA无法识别给定虚拟地址范围内的值
如果包含bss的话, 就会这样子…
明天早起继续看
跳转
G 跳转到…
Esc 后退重命名
N举了一个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
; 不需要调用方清理参数
搜索
ALT + T 文本搜索
ALT + B 二进制搜索代码数据互换
U(undefine) 取消定义 code变成原始一个一个byte
C(code) data -> code
D(data) code -> data
在数据转盘里切换data种类
数据转盘里设置 options -> Steup data types
数据相关
db 1字节 byte
dw 2字节 word
dd 4字节 dword
dq 8字节 qword数组
选中数据开头,Edit -> Array
,可以创建数组
这样子关于数组的访问就是基于Array_head + offset
的形式
后来又遇到了问题…我的数组每个元素多大…怎么在建立数组菜单里没法选择
然后发现是需要先把数据开头第一个元素变成想要的类型, 比如word
然后再新建数组, 得到的就是数组元素大小就是和第一个元素一样的
- 结构体
结构体, 几乎没法直接分辨是用了结构体
要自己手动识别, 然后添加
一般一个变量(加不同间隔)偏移量的..这个变量可能就是某种类型的
特别是看到有的时候会把什么函数指针啊, 之类的赋值给他的成员
基本就是个类or结构体了
在建立结构体的时候要注意那个, emmmmm, 注意在结构体末尾那一行点新建元素…不是开头那一行, 具体是怎么的来着…忘记了, 算了, 2333333
C++
C++ 果然复杂的…毛线一样
this
所有非静态C++成员函数都是用this指针
把this看做是传递到所有非静态成员函数的第一个隐含参数
MS VC++ 遵循thiscall, 把this传入到ECX寄存器
GUN g++ 把this看成最左边的参数,最后压入栈虚函数 虚表
包含虚函数的类
的第一个数据成员是一个指针,叫做虚表指针(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脚本
- File > Script
- File > IDC Command
- 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 eax
里eax
的值实际上是能确定的, 但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]
- 加壳…
加了壳, 尤其是UPX这样子的壳, 没办法静态分析了就
就要先脱壳
加壳后的特征:
1. 有非标准段名称
1. 一个或者多个程序既可以写又可以执行
1. Functions, Imports, Strins 很少有内容
一般壳用到的API (windows…)
HINSTANCE LoadLibrary(LPCTSTR lpLibFileName) // 根据名称加载dll, 返回句柄 HMODULE GetModuleHandle(LPCTSTR lpModuleName) // 获取dll句柄 FARPROC GetProcAddress( HMODULE hModule, // DLL模块句柄 LPCSTR lpProcName // 函数名 )
先把dll加载进来, 最后获取函数
一般的,可能dll早已经加载进来, 那么直接获取句柄, 然后获取函数就可以了有目的的攻击分析工具
woc, 这个厉害了…
反动态分析
- 检测是在虚拟机运行还是本机运行
- 检测检查工具
- 检测调试器(反调试)
- isDebuggerPresent (win)
- ptrace (Linux)
这一块收藏过一篇文章, 然后再看一下
自己学习一丢丢C++
c++感觉会push好多东西.导致IDA里看到某些函数参数错误
就比如我这里的cout << 2 << 3
转化得到的其实是cout << 2
和cout << 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进制, 然后右键选单里才有变成负数…
右键的时候稍微靠后一点…离的太近可能出不来