如何从CheckUserPermissionAccess函数汇编代码中提取用户名和密码?
分析CheckUserPermissionAccess汇编代码以获取用户名和密码
问题描述
如何通过分析CheckUserPermissionAccess函数的汇编代码获取用户名和密码?以下是用objdump -drwC生成的汇编代码(含重定位信息):
0000000000000120 <CheckUserPermissionAccess()>: 120: 55 push %rbp 121: 48 89 e5 mov %rsp,%rbp 124: 53 push %rbx 125: 48 83 ec 48 sub $0x48,%rsp 129: 64 48 8b 04 25 28 00 00 00 mov %fs:0x28,%rax 132: 48 89 45 e8 mov %rax,-0x18(%rbp) 136: 31 c0 xor %eax,%eax 138: 48 8d 45 bb lea -0x45(%rbp),%rax 13c: 48 89 c7 mov %rax,%rdi 13f: e8 00 00 00 00 callq 144 <CheckUserPermissionAccess()+0x24> 140: R_X86_64_PLT32 std::allocator<char>::allocator()-0x4 144: 48 8d 55 bb lea -0x45(%rbp),%rdx 148: 48 8d 45 c0 lea -0x40(%rbp),%rax 14c: 48 8d 35 00 00 00 00 lea 0x0(%rip),%rsi # 153 <CheckUserPermissionAccess()+0x33> 14f: R_X86_64_PC32 .rodata+0xe9 153: 48 89 c7 mov %rax,%rdi 156: e8 00 00 00 00 callq 15b <CheckUserPermissionAccess()+0x3b> 157: R_X86_64_PLT32 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)-0x4 15b: 48 8d 45 bb lea -0x45(%rbp),%rax 15f: 48 89 c7 mov %rax,%rdi 162: e8 00 00 00 00 callq 167 <CheckUserPermissionAccess()+0x47> 163: R_X86_64_PLT32 std::allocator<char>::~allocator()-0x4 167: c7 45 bc 00 00 00 00 movl $0x0,-0x44(%rbp) 16e: 48 8d 35 00 00 00 00 lea 0x0(%rip),%rsi # 175 <CheckUserPermissionAccess()+0x55> 171: R_X86_64_PC32 .rodata+0xea 175: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 17c <CheckUserPermissionAccess()+0x5c> 178: R_X86_64_PC32 std::cout-0x4 17c: e8 00 00 00 00 callq 181 <CheckUserPermissionAccess()+0x61> 17d: R_X86_64_PLT32 std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)-0x4 181: 48 8d 35 00 00 00 00 lea 0x0(%rip),%rsi # 188 <CheckUserPermissionAccess()+0x68> 184: R_X86_64_PC32 username-0x4 188: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 18f <CheckUserPermissionAccess()+0x6f> 18b: R_X86_64_PC32 std::cin-0x4 18f: e8 00 00 00 00 callq 194 <CheckUserPermissionAccess()+0x74> 190: R_X86_64_PLT32 std::basic_istream<char, std::char_traits<char> >& std::operator>> <char, std::char_traits<char> >(std::basic_istream<char, std::char_traits<char> >&, char*)-0x4 194: 48 8d 35 00 00 00 00 lea 0x0(%rip),%rsi # 19b <CheckUserPermissionAccess()+0x7b> 197: R_X86_64_PC32 .rodata+0x101 19b: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 1a2 <CheckUserPermissionAccess()+0x82> 19e: R_X86_64_PC32 std::cout-0x4 1a2: e8 00 00 00 00 callq 1a7 <CheckUserPermissionAccess()+0x87> 1a3: R_X86_64_PLT32 std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)-0x4 1a7: 48 8d 45 c0 lea -0x40(%rbp),%rax 1ab: 48 89 c6 mov %rax,%rsi 1ae: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 1b5 <CheckUserPermissionAccess()+0x95> 1b1: R_X86_64_PC32 std::cin-0x4 1b5: e8 00 00 00 00 callq 1ba <CheckUserPermissionAccess()+0x9a> 1b6: R_X86_64_PLT32 std::basic_istream<char, std::char_traits<char> >& std::operator>> <char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)-0x4 1ba: 48 8d 45 c0 lea -0x40(%rbp),%rax 1be: 48 8d 35 00 00 00 00 lea 0x0(%rip),%rsi # 1c5 <CheckUserPermissionAccess()+0xa5> 1c1: R_X86_64_PC32 .rodata+0x118 1c5: 48 89 c7 mov %rax,%rdi 1c8: e8 00 00 00 00 callq 1cd <CheckUserPermissionAccess()+0xad> 1c9: R_X86_64_PLT32 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::compare(char const*) const-0x4 1cd: 89 45 bc mov %eax,-0x44(%rbp) 1d0: 83 7d bc 00 cmpl $0x0,-0x44(%rbp) 1d4: 75 07 jne 1dd <CheckUserPermissionAccess()+0xbd> 1d6: bb 01 00 00 00 mov $0x1,%ebx 1db: eb 05 jmp 1e2 <CheckUserPermissionAccess()+0xc2> 1dd: bb 02 00 00 00 mov $0x2,%ebx 1e2: 48 8d 45 c0 lea -0x40(%rbp),%rax 1e6: 48 89 c7 mov %rax,%rdi 1e9: e8 00 00 00 00 callq 1ee <CheckUserPermissionAccess()+0xce> 1ea: R_X86_64_PLT32 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()-0x4 1ee: 89 d8 mov %ebx,%eax 1f0: 48 8b 4d e8 mov -0x18(%rbp),%rcx 1f4: 64 48 33 0c 25 28 00 00 00 xor %fs:0x28,%rcx 1fd: 74 3b je 23a <CheckUserPermissionAccess()+0x11a> 1ff: eb 34 jmp 235 <CheckUserPermissionAccess()+0x115> 201: 48 89 c3 mov %rax,%rbx 204: 48 8d 45 bb lea -0x45(%rbp),%rax 208: 48 89 c7 mov %rax,%rdi 20b: e8 00 00 00 00 callq 210 <CheckUserPermissionAccess()+0xf0> 20c: R_X86_64_PLT32 std::allocator<char>::~allocator()-0x4 210: 48 89 d8 mov %rbx,%rax 213: 48 89 c7 mov %rax,%rdi 216: e8 00 00 00 00 callq 21b <CheckUserPermissionAccess()+0xfb> 217: R_X86_64_PLT32 _Unwind_Resume-0x4 21b: 48 89 c3 mov %rax,%rbx 21e: 48 8d 45 c0 lea -0x40(%rbp),%rax 222: 48 89 c7 mov %rax,%rdi 225: e8 00 00 00 00 callq 22a <CheckUserPermissionAccess()+0x10a> 226: R_X86_64_PLT32 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()-0x4 22a: 48 89 d8 mov %rbx,%rax 22d: 48 89 c7 mov %rax,%rdi 230: e8 00 00 00 00 callq 235 <CheckUserPermissionAccess()+0x115> 231: R_X86_64_PLT32 _Unwind_Resume-0x4 235: e8 00 00 00 00 callq 23a <CheckUserPermissionAccess()+0x11a> 236: R_X86_64_PLT32 __stack_chk_fail-0x4 23a: 48 83 c4 48 add $0x48,%rsp 23e: 5b pop %rbx 23f: 5d pop %rbp 240: c3 retq
我曾尝试查看cmp指令以确定比对的字符,但发现仅存在一条cmp指令,这似乎意味着密码仅为单个字符,显然不合理。请问该如何从此汇编代码中获取用户名和密码?
分析与解决方法
1. 关于密码的误解
你看到的唯一cmp指令(1d0: cmpl $0x0,-0x44(%rbp))并不是直接比对单个字符,而是判断std::string::compare方法的返回值:
1c8处调用的std::__cxx11::basic_string::compare会逐字符比对输入密码和硬编码的正确密码,返回0表示完全匹配;1d0的cmp只是检查返回值是否为0,以此判断密码是否正确,所以密码并不是单个字符,完整的比对逻辑在C++标准库的compare函数内部,不会出现在当前函数的汇编中。
2. 获取正确密码
正确密码硬编码在程序的只读数据段(.rodata)中,对应汇编里1be行的重定位.rodata+0x118。你可以用以下方法获取:
- 执行
objdump -s -j .rodata <二进制文件名>查看只读数据段内容,找到偏移0x118处的字符串; - 或者用十六进制编辑器打开二进制文件,定位到
.rodata段的对应偏移位置,读取字符串。
3. 获取用户名
汇编中181行的重定位是username-0x4,说明程序存在一个全局字符数组username,用于接收输入的用户名:
- 如果用户名是硬编码的正确值,查看
.data段中username符号对应的初始内容即可; - 如果用户名的验证逻辑不在当前函数中,可能需要结合其他代码段分析,但从当前函数看,它仅负责接收用户名输入,没有做验证。
内容的提问来源于stack exchange,提问作者FireMonkey
相关产品推荐
相关产品推荐

