翻译并且进行了部分的筛选。
首先还是得尽量让代码比较好看,所以推荐一个 ida 插件,下面很多结果为了好看都使用了这个插件
这个可以对函数名进行一定程度的重命名,然而好像有点 bug,尤其是对于一些较大的 rust 程序。。。。
好吧,下面是原文的一部分内容
一个空的程序
首先是 main 函数。需要注意的不仅仅是 main 函数(rust 程序的),还有 lang_start 函数
点进来看
除了有 c 语言版的函数参数,还多了 a1 传进 lang_start_internal,虽然很显然是原来 main 的指针,还是看一下 rs 源码吧
确实是这样,可以看出注册了有异常处理相关的东西,在 Windows 下是 VEH,在 linux 下是 stack unwind
下面是 win 的
然后还有一点,对于 linux(win 我没找到),rs 有垃圾回收机制,如图
这个会被 internal 函数调用。但是,这个 drop 是可以自定义的(也许可以出题?坏笑)
好吧,基础流程就到这里,下面会讲一下别的例如字符串啥的
Hello World
fn main() {println!("Hello, world!");
}
代码如上,非常的简单。
以下是编译完的结果
对于函数 core::fmt::Arguments::new_v1,很显然是在初始化下面要调用的 println 所需要的函数参数。而 off_4C1E8,点进去就能发现是我们储存的字符串。
不过在继续讲这个函数原理之前要提到另一个问题,就是 rust 中的字符串储存问题。点进去就能发现,其实 rs 储存字符串,也就是 &str, 采用的是不同于 c 语言的方式,使用了字符串的指针 + 长度的方式进行储存。
In [1]: 0xe
Out[1]: 14
In [2]: len("Hello, world!\n")
Out[2]: 14
所以其实可以说是这样
struct rs_string
{
__int64 ptr_string;
__int64 length;
};
但是,实际上点进指针就能发现,真正储存的时候还是以传统 c 风格进行了储存,因为最后还是出现了 0 位
那么看完字符串的基本问题后,我们来看一下这个经常出现的 ArgumnentV1 到底是干什么的?不妨来看一下源码
和我们直接反编译出来的其实很像。而原作者提到,他认为别的地方不是很容易出现这个,这个函数的出现往往预示着关键的字符串操作,如准备进行格式化的输出等。
他还提到了一点,对于 rust 程序有一点比较特别,就是在准备输出时会使用一条奇怪的指令,在伪代码中看起来是这样的:
_InterlockedCompareExchange((volatile signed __int32 *)v5 + 4, 1, 0)
而其实这是一条不常用的汇编代码
lock cmpxchg [rbx+10h], ecx
有可能也能凭借这一点进行判断,尤其是被扣了符号表的情况下
(真的是有这样的题的。。。)