如何从 MS-Windows 操作系统反编译 Linux .so 库文件?

逆向工程 工具 反编译 反编译
2021-06-21 03:40:26

我想反编译Linux.so文件。

  • 任何.so在基于 MS-Windows 的操作系统中反编译文件的工具
  • 任何反编译.so文件的工具/方法
3个回答

正如 0xea 所说,该.so文件只是常规的可执行文件,但以动态库样式打包。

我知道您专门询问了 MS-Windows 工具,但我将忽略这一点,因为 0xea 已经对此做出了答复。我将尝试解释如何使用 UNIX 工具来做到这一点。

从库中提取函数

第一步是提取此库中存在的所有函数的名称,以了解它的外观。我将使用/usr/lib/libao.so.4.0.0(我在我的系统上使用的一个随机库,它足够小,可以作为一个例子)。

首先,运行readelf它看看你在做什么:

#> readelf -a /usr/lib/libao.so.4.0.0

ELF Header:
Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
Class:                             ELF64
Data:                              2's complement, little endian
Version:                           1 (current)
OS/ABI:                            UNIX - System V
ABI Version:                       0
Type:                              DYN (Shared object file)
Machine:                           Advanced Micro Devices X86-64
Version:                           0x1
Entry point address:               0x1fb0
Start of program headers:          64 (bytes into file)
Start of section headers:          35392 (bytes into file)
Flags:                             0x0
Size of this header:               64 (bytes)
Size of program headers:           56 (bytes)
Number of program headers:         6
Size of section headers:           64 (bytes)
Number of section headers:         29
Section header string table index: 28

[...lots of tables and other information...]

您可能会注意到readelf检测到一个入口点。事实上,它确实对应于负责初始化内存以正确加载库的过程。但是,这对我们没有用。

查看 的其余输出readelf -a,动态符号表 ( .dynsym) 非常有用,因为它包含如下条目:

43: 00000000000038e0  1302 FUNC    GLOBAL DEFAULT   13 ao_play@@LIBAO4_1.1.0

事实上,这个动态库中的每个函数都在这个列表中,你可以像这样简单地提取它:

#> readelf -a /usr/lib/libao.so.4.0.0 | grep LIBAO4_1.1.0 | grep FUNC

43: 00000000000038e0  1302 FUNC    GLOBAL DEFAULT   13 ao_play@@LIBAO4_1.1.0
44: 0000000000003670   177 FUNC    GLOBAL DEFAULT   13 ao_append_option@@LIBAO4_1.1.0
45: 00000000000040e0    70 FUNC    GLOBAL DEFAULT   13 ao_driver_info@@LIBAO4_1.1.0
46: 0000000000002d40  2349 FUNC    GLOBAL DEFAULT   13 ao_initialize@@LIBAO4_1.1.0
48: 0000000000003ef0   484 FUNC    GLOBAL DEFAULT   13 ao_default_driver_id@@LIBAO4_1.1.0
49: 0000000000003e00   144 FUNC    GLOBAL DEFAULT   13 ao_close@@LIBAO4_1.1.0
50: 0000000000005070   239 FUNC    GLOBAL DEFAULT   13 ao_open_file@@LIBAO4_1.1.0
51: 0000000000005160     7 FUNC    GLOBAL DEFAULT   13 ao_open_live@@LIBAO4_1.1.0
52: 0000000000003730    18 FUNC    GLOBAL DEFAULT   13 ao_append_global_option@@LIBAO4_1.1.0
53: 0000000000003790   326 FUNC    GLOBAL DEFAULT   13 ao_shutdown@@LIBAO4_1.1.0
54: 0000000000004130    16 FUNC    GLOBAL DEFAULT   13 ao_driver_info_list@@LIBAO4_1.1.0
55: 0000000000003750    60 FUNC    GLOBAL DEFAULT   13 ao_free_options@@LIBAO4_1.1.0
56: 0000000000004140    13 FUNC    GLOBAL DEFAULT   13 ao_is_big_endian@@LIBAO4_1.1.0
57: 0000000000003e90    92 FUNC    GLOBAL DEFAULT   13 ao_driver_id@@LIBAO4_1.1.0

你在这里得到的是函数的名称,这些函数的名称.so加上它们在内存中的代码地址(第一列)。

请注意,您还可以使用以下方法获取此信息objdump

#> objdump -T /usr/lib/libao.so.4.0.0 | grep LIBAO4_1.1.0 | grep DF
00000000000038e0 g    DF .text  0000000000000516  LIBAO4_1.1.0 ao_play
0000000000003670 g    DF .text  00000000000000b1  LIBAO4_1.1.0 ao_append_option
00000000000040e0 g    DF .text  0000000000000046  LIBAO4_1.1.0 ao_driver_info
0000000000002d40 g    DF .text  000000000000092d  LIBAO4_1.1.0 ao_initialize
0000000000003ef0 g    DF .text  00000000000001e4  LIBAO4_1.1.0 ao_default_driver_id
0000000000003e00 g    DF .text  0000000000000090  LIBAO4_1.1.0 ao_close
0000000000005070 g    DF .text  00000000000000ef  LIBAO4_1.1.0 ao_open_file
0000000000005160 g    DF .text  0000000000000007  LIBAO4_1.1.0 ao_open_live
0000000000003730 g    DF .text  0000000000000012  LIBAO4_1.1.0 ao_append_global_option
0000000000003790 g    DF .text  0000000000000146  LIBAO4_1.1.0 ao_shutdown
0000000000004130 g    DF .text  0000000000000010  LIBAO4_1.1.0 ao_driver_info_list
0000000000003750 g    DF .text  000000000000003c  LIBAO4_1.1.0 ao_free_options
0000000000004140 g    DF .text  000000000000000d  LIBAO4_1.1.0 ao_is_big_endian
0000000000003e90 g    DF .text  000000000000005c  LIBAO4_1.1.0 ao_driver_id

拆解各个功能

现在是使用的时候了objdump(或者如果你能得到一个更高级的反汇编器)。给定函数列表及其在二进制文件中的地址,您可以简单地objdump为每个函数运行,如下所示:

objdump -d /usr/lib/libao.so.4.0.0 --start-address=0x3730

请注意,由于objdump使用线性扫描,拆卸可能不准确(请参见以下示例),并且您还必须自己决定何时结束。

#> objdump -d /usr/lib/libao.so.4.0.0 --start-address=0x3730

/usr/lib/libao.so.4.0.0:     file format elf64-x86-64

Disassembly of section .text:
0000000000003730 <ao_append_global_option>:
 3730:       48 89 f2                mov    %rsi,%rdx
 3733:       48 89 fe                mov    %rdi,%rsi
 3736:       48 8d 3d cb 52 20 00    lea    0x2052cb(%rip),%rdi
 373d:       e9 4e e6 ff ff          jmpq   1d90 <ao_append_option@plt>
 3742:       66 66 66 66 66 2e 0f    data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
 3749:       1f 84 00 00 00 00 00 

0000000000003750 <ao_free_options>:
 3750:       55                      push   %rbp
 3751:       53                      push   %rbx
 3752:       48 89 fb                mov    %rdi,%rbx
 3755:       48 83 ec 08             sub    $0x8,%rsp
 3759:       48 85 ff                test   %rdi,%rdi
 375c:       74 27                   je     3785 <ao_free_options+0x35>
 375e:       66 90                   xchg   %ax,%ax
 3760:       48 8b 3b                mov    (%rbx),%rdi
 3763:       48 8b 6b 10             mov    0x10(%rbx),%rbp
 3767:       e8 c4 e5 ff ff          callq  1d30 <free@plt>
 376c:       48 8b 7b 08             mov    0x8(%rbx),%rdi
 3770:       e8 bb e5 ff ff          callq  1d30 <free@plt>
 3775:       48 89 df                mov    %rbx,%rdi
 3778:       48 89 eb                mov    %rbp,%rbx
 377b:       e8 b0 e5 ff ff          callq  1d30 <free@plt>
 [... clip ...]

而且,这就是全部(但是,获得比objdump!更好的反汇编程序)。

Linux 共享对象文件也是 ELF!任何适用于“常规”ELF 文件的反编译器也适用于 SO 文件。

也就是说,您可以像往常一样使用 IDA Pro 来拆卸它们。如果您拥有带有 Hex-rays 反编译器的 IDA Pro 许可证,则可以使用它。如果你没有 Hex-rays,你可以试试ida-decompiler插件来得到一些结果。它是开源的,但远不如 Hex-rays 先进。

反汇编和反编译之间的区别在于,反汇编二进制代码将为您提供等效的汇编代码。另一方面,反编译意味着将原始汇编代码转换为高级语言(在本例中为 C)的过程。

反编译汇编代码并非易事,因为在汇编级别上丢失了更高级别代码的许多抽象。恢复这些抽象是困难的部分。
例如,您通常会丢失变量名称。

另一方面,将一些字节码反编译成更高级的语言,比如将 java 字节码反编译为 java,稍微容易一些,因为这些抽象中的许多都保留在字节码中。

用目前的工具自动反编译汇编代码并不完美,它的目的是作为敬仰的帮手。您还可以通过识别代码结构(如 for 循环、if 语句、开关等)手动将汇编代码反编译为高级语言。

如果反汇编没问题,您可以通过 seppel 使用 hteditor http://hte.sourceforge.net/

使用 samba 从 linux 机器复制 .so 文件

并将 so 文件提供给 hteditor

使用来自该死的小型 linux 的 libc.so.6 的示例

假设 samba 在 vm 中启动并运行,并且在 Windows 主机中创建了一个共享文件夹说 c:\sharedwithvm

from the linux machine 

cp ../..../lib/libc.so.6 /mnt//sharedwithvm

in the windows machine 

C:\>cd sharedwithvm

C:\sharedwithvm>dir /b
libc.so.6

C:\sharedwithvm>f:\hteditor\2022\ht-2.0.22-win32.exe libc.so.6

hteditor 将以十六进制视图打开

f6 select elf\image

f8 symbols type fo

60490 │ func │ fopen                                ▲

双击查看拆解

<.text> @00060490  push ebp
fopen+0
   ..... ! ;********************************************************
   ..... ! ; function fopen (global)
   ..... ! ;********************************************************
   ..... ! fopen:                          ;xref c189a7 c262da c74722
   ..... !                                 ;xref c93c74 c94cd5 cd23c4
   ..... !                                 ;xref cd3617 cd37c6 cd3a1a
   ..... !                                 ;xref cd7061 cd717f cd729f
   ..... !                                 ;xref ce50e3 ce67e6 ce7581
   ..... !                                 ;xref cef095 cf0302
   ..... !   push        ebp
   60491 !   mov         ebp, esp
   60493 !   sub         esp, 18h
   60496 !   mov         [ebp-4], ebx
   60499 !   mov         eax, [ebp+0ch]
   6049c !   call        sub_15c8d
   604a1 !   add         ebx, offset_cab57
   604a7 !   mov         dword ptr [esp+8], 1
   604af !   mov         [esp+4], eax
   604b3 !   mov         eax, [ebp+8]