2026/3/31 7:19:46
网站建设
项目流程
网站建设需求有什么用,wordpress改了ip,广州 网站设计,网站建设方案平台选择Rust in your disassembler
今年在Atr2con会议上#xff0c;我将展示如何破解一个用Rust编写的CrackMe二进制文件。由于会议是在线形式#xff0c;我选择主要以大型演示的形式录制#xff0c;仅使用极少的幻灯片。然而#xff0c;你们中的一些人可能希望了解一些细节或理论…Rust in your disassembler今年在Atr2con会议上我将展示如何破解一个用Rust编写的CrackMe二进制文件。由于会议是在线形式我选择主要以大型演示的形式录制仅使用极少的幻灯片。然而你们中的一些人可能希望了解一些细节或理论。Rust编译器所做的事情非常巧妙且有趣。字符串是胖指针这与C语言不同在C语言中你的字符串实际上只是一个指向字符的简单指针。在Rust中你的内联字符串将指向一个包含以下内容的结构长度你字符串的长度。不需要像C语言那样在字符串末尾用\0结尾。一个指向字符串字符的指针。Radare2将这些字符串显示为reloc.fixup.xxxx。例如下面的字符串显然位于地址0x5e790。如果我们查看该地址的字节可以清楚地看到指针6bc0 0400 - 0x04c06b然后是长度0x25。我们确认字符位于0x04c06b。;0x5e790;k\xc0\x04 0x00008b6a 488d051f5c.. lea rax,reloc.fixup.Space_Station_Airlock_Control_S [0x00008b40] px10 0x5e790 - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x0005e790 6bc0 0400 0000 0000 2500 k.......%. [0x00008b40] px0x25 0x04c06b - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x0004c06b 5370 6163 6520 5374 6174 696f 6e20 4169 Space Station Ai 0x0004c07b 726c 6f63 6b20 436f 6e74 726f 6c20 5379 rlock Control Sy 0x0004c08b 7374 656d 0a stem.单态化你可能听说过多态。这是指一个给定的函数能够操作不同的类型。单态化则“相反”我们确保每种类型严格对应一个函数。Rust编译器会自动使用单态化——这是出于优化的原因比如不需要虚函数表。当它遇到泛型函数时在底层它实际上会为每种类型生成一个函数的汇编代码。开发者看不到这一点这是编译器的工作。// 泛型函数fnsquareT:std::ops::MulOutputTCopy(x:T)-T{x*x}fnmain(){letasquare(3i32);// 生成 square::i32letbsquare(2.5f64);// 生成 square::f64}编译器也经常为闭包这样做。闭包闭包是一个捕获其环境的函数。在下面的例子中add_x是一个闭包。它捕获了环境其中x 5。调用add_x(3)返回 8。fnmain(){letx5;letadd_x|y|xy;println!({},add_x(3));}Rust编译器的具体行为很大程度上取决于优化级别。假设你用-C opt-level0编译这段代码。[0x00007960] pdi sym.main::main::h8f1c9e3495794b54 0x00007b90 sym.main::main::h8f1c9e3495794b54: 0x00007b90 4883ec68 sub rsp, 0x68 0x00007b94 c7442404050. mov dword [rsp 4], 5 0x00007b9c 488d442404 lea rax, [rsp 4] 0x00007ba1 4889442408 mov qword [rsp 8], rax 0x00007ba6 488d7c2408 lea rdi, [rsp 8] 0x00007bab be03000000 mov esi, 3 0x00007bb0 e85b000000 call sym.main::main::__u7b__u7b_closure_u7d__u7d_::h0ea7a13e6c14ebb2 0x00007bb5 89442464 mov dword [rsp 0x64], eax编译器为我们的主函数生成了一个特定的闭包。它被命名为sym.main::main::__u7b__u7b_closure_u7d__u7d_::h0ea7a13e6c14ebb2。该闭包的参数是第一个参数在rdi中rsp 8。这是闭包环境。它包含一个指向rsp 4的指针而该地址存放着值 5。第二个参数在esi中3。这是传递给闭包的参数。在闭包的汇编代码中我们有一些针对整数操作的指令。0x00007c11 488b07 mov rax, qword [rdi] 0x00007c14 0330 add esi, dword [rax] ... 0x00007c1f 8b442404 mov eax, dword [rsp 4]如果闭包被用于浮点数则会生成另一个闭包并带有不同的指令。这就是单态化。我们可以通过创建一个同时适用于浮点数和整数的闭包来更好地观察这一点usestd::ops::Add;fnget_adderT(x:T)-implFn(T)-TwhereT:AddOutputTCopy,{move|y|xy}fnmain(){letadd_intget_adder(5);letadd_floatget_adder(5.0);println!({},add_int(3));println!({},add_float(4.5));}现在如果我们检查汇编代码会注意到编译器生成了2个get_adder函数。[0x00007960] afl~main 0x00007c00 11 sym.main::get_adder::hba4b3b420a6e866b 0x00007c10 13 sym.main::get_adder::hbe8e2ff9c2a8357d 0x00007c20 122 sym.main::get_adder::__u7b__u7b_closure_u7d__u7d_::h6ff0b01bf90189e9 0x00007c40 117 sym.main::get_adder::__u7b__u7b_closure_u7d__u7d_::h72c4b1cd2fd53136 0x00007c60 1251 sym.main::main::h8f1c9e3495794b54如果我们检查第一个get_adder的汇编代码会发现它适用于浮点数0x00007c20 sym.main::get_adder::__u7b__u7b_closure_u7d__u7d_::h6ff0b01bf90189e9: 0x00007c20 50 push rax 0x00007c21 0f28c8 movaps xmm1, xmm0 0x00007c24 f20f1007 movsd xmm0, qword [rdi] 0x00007c28 488d3d19ee0. lea rdi, [rip 0x4ee19] 0x00007c2f e87cfeffff call sym.__f64_as_core::ops::arith::Add_::add::hf4bd57df382c73d6 0x00007c34 58 pop rax 0x00007c35 c3 ret而第二个get_adder适用于整数0x00007c40 sym.main::get_adder::__u7b__u7b_closure_u7d__u7d_::h72c4b1cd2fd53136: 0x00007c40 50 push rax 0x00007c41 8b3f mov edi, dword [rdi] 0x00007c43 488d15feed0. lea rdx, [rip 0x4edfe] 0x00007c4a e871feffff call sym.__i32_as_core::ops::arith::Add_::add::h471fa892cd8f10a4 0x00007c4f 59 pop rcx 0x00007c50 c3 ret脱糖在Rust中开发者通常调用像obj.blah()这样的方法。Rust编译器在内部将其转换为更明确但不那么“甜”的形式class::blah(obj)。letobjMyObject{value:10};obj.blah();// 语法糖查看下面生成的汇编代码; set value 10 0x00007bc4 c744240c0a00. mov dword [rsp 0xc], 0xa ; put obj in RDI (1st argument of blah()) 0x00007bcc 488d7c240c lea rdi, [rsp 0xc] ; call blah() with address of obj as argument 0x00007bd1 e8baffffff call sym.sugar::MyObject::blah::h059bdb1e25fa70c4宏在Rust中用于显示内容的函数println!是一个宏而不是一个“真正的”函数。因此在汇编代码中你不会看到对println!的调用这个“函数”并不存在而是看到设置格式字符串和参数。构建 Arguments 结构体。调用dbg._print它实际上会调用dbg.write_fmt,dbg.write…我建议你阅读这篇文章以获取更多细节。下面的汇编代码是由一个 Hello World 程序生成的。0x00007b20 sym.print::main::h13b5f0e40e4e7865: 0x00007b20 4883ec38 sub rsp, 0x38 ; 在栈上为 Arguments 对象分配空间 0x00007b24 488d7c2408 lea rdi, [rsp 8] ; 指向字符串 Hello World 的胖指针 0x00007b29 488d35d0a30. lea rsi, [rip 0x4a3d0] 0x00007b30 e83bffffff call sym.core::fmt::rt::__impl_core::fmt::Arguments_::new_const::ha519b55ee7e59acf 0x00007b35 488d7c2408 lea rdi, [rsp 8] ; 通过 GOT 调用 dbg._print 例程 0x00007b3a ff1550cf0400 call qword [rip 0x4cf50] 0x00007b40 4883c438 add rsp, 0x38 0x00007b44 c3 ret注意对dbg._print的调用是间接的dbg._print的 GOT全局偏移表条目位于rip 0x4cf50。Radare2 将其显示为一个reloc.fixup[0x00007b20] px10 reloc.fixup.UHSHxHH_ - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x00054a90 c0430200 00000000 0000 .C........ [0x00007b20] pd10 0x0243c0 ;-- std::io::stdio::_print::h915f3273edec6464: ;DATA XREF from reloc.fixup.UHSHxHH_ ┌206: dbg._print (int64_t arg1); │- args (rdi) vars (13: sp[0x18..0x80]) │ 0x000243c0 55 push rbp ; sync.rs:0:13 ; void _print();— CryptaxCSD0tFqvECLokhw9aBeRqtFmyXmRsBISmPE7edMOI2OK8XHtAZcBhDmHp75CbukkcV4OE5l5gwOQpJ1KPqBQB2mY1bHR5IDRIauIsx0/nRk更多精彩内容 请关注我的个人公众号 公众号办公AI智能小助手对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号网络安全技术点滴分享