|
1 | | -# Binary Diffing |
| 1 | +# Rz-Diff (binary and text diffing utility) |
2 | 2 |
|
3 | | -This section is based on the http://rizin.today article "[binary diffing](https://rizinorg.github.io/blog/posts/binary-diffing/)" |
| 3 | +## Distance |
4 | 4 |
|
5 | | -Without any parameters, `rz-diff` by default shows what bytes are changed and their corresponding offsets: |
| 5 | +For bulk processing, you may want to have a higher-level overview of differences. |
| 6 | + |
| 7 | +The `-d` option serves to calculate the distance between the two binaries using either myers algorithm or the levenshtein algorithm. |
| 8 | + |
| 9 | +``` |
| 10 | + -d --------> myers (myers algorithm) |
| 11 | + |----> leven (levenshtein algorithm) |
| 12 | +``` |
| 13 | + |
| 14 | +### Myers algorithm: |
| 15 | + |
| 16 | +In the [Myers](https://epubs.siam.org/doi/10.1137/S0097539794264810) algorithm for edit distance, the cost of an insertion or deletion is 1 and the cost of a replacement is 2. |
| 17 | +The theorem leads directly to an O(k) algorithm for incrementally computing a new solution from an old one, as contrasts the O(k2 ) time required to compute a solution from scratch. |
| 18 | +Thus the algorithm performs well when the two strings are similar. |
| 19 | + |
| 20 | +`rz-diff -d myers /bin/true /bin/false` |
| 21 | + |
| 22 | +output: |
| 23 | +``` |
| 24 | +similarity: 0.974 |
| 25 | +distance: 2046 |
| 26 | +``` |
| 27 | + |
| 28 | +### Levenshtein distance: |
| 29 | + |
| 30 | +[Levenshtein](https://en.wikipedia.org/wiki/Levenshtein_distance) distance is a string metric for measuring the difference between two sequences. Informally, the Levenshtein distance between two words is the minimum number of single-character edits (insertions, deletions or substitutions) required to change one word into the other. |
| 31 | + |
| 32 | +`rz-diff -d leven /bin/true /bin/false` |
| 33 | + |
| 34 | +output: |
| 35 | +``` |
| 36 | +similarity: 0.974 |
| 37 | +distance: 2046 |
| 38 | +``` |
| 39 | + |
| 40 | +## Hexadecimal Diffing: |
| 41 | + |
| 42 | +`-H` The hexadecimal displays the hexdump of file0 vs file1 in a side-by-side window. Navigational keys allows easily parsing through the hexdump of the files individually. |
| 43 | + |
| 44 | + - `1` and `2` : to move to the next or previous page. |
| 45 | + - `Z` and `A` : allows parsing forward and backward through file0, byte by byte. |
| 46 | + - `C` and `D` : allows parsing forward and backward through file1, byte by byte. |
| 47 | + - `G` and `B` : seeks the end and beginning of the files. |
| 48 | + - `N` and `M` : takes you to the Next and the Previous differing byte in the files respectively. |
| 49 | + - `/\` and `\/` : parsing both binaries simultaneously, 16 bytes a time. |
| 50 | + - `<` and `>` : parsing both binaries simultaneously, by 1 byte. |
| 51 | + - `: <seek address in hex/decimal>` : seeks the address provided and bring the window to start dump from the seeked address. |
| 52 | + - `?` : shows the help screen in the visual mode which can be exited with 'q'/esc keys. |
| 53 | + |
| 54 | +The bytes that differ are: `rz-diff -H /bin/true /bin/false` |
| 55 | + |
| 56 | +``` |
| 57 | +.---------- [ 0 | 9958]( true )-------------------------------------------------------------------- [ 0 | 9958]( false )---------------------------------------------------------. |
| 58 | +| 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F | |
| 59 | +|0x0000000000000000 | 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 | .ELF............ | 0x0000000000000000 | 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 | .ELF............ | |
| 60 | +|0x0000000000000010 | 03 00 3e 00 01 00 00 00 10 26 00 00 00 00 00 00 | ..>......&...... | 0x0000000000000010 | 03 00 3e 00 01 00 00 00 20 26 00 00 00 00 00 00 | ..>..... &...... | |
| 61 | +|0x0000000000000020 | 40 00 00 00 00 00 00 00 d8 91 00 00 00 00 00 00 | @............... | 0x0000000000000020 | 40 00 00 00 00 00 00 00 d8 91 00 00 00 00 00 00 | @............... | |
| 62 | +|0x0000000000000030 | 00 00 00 00 40 00 38 00 0d 00 40 00 1e 00 1d 00 | ....@.8...@..... | 0x0000000000000030 | 00 00 00 00 40 00 38 00 0d 00 40 00 1e 00 1d 00 | ....@.8...@..... | |
| 63 | +|0x0000000000000040 | 06 00 00 00 04 00 00 00 40 00 00 00 00 00 00 00 | ........@....... | 0x0000000000000040 | 06 00 00 00 04 00 00 00 40 00 00 00 00 00 00 00 | ........@....... | |
| 64 | +|0x0000000000000050 | 40 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 | @.......@....... | 0x0000000000000050 | 40 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 | @.......@....... | |
| 65 | +|0x0000000000000060 | d8 02 00 00 00 00 00 00 d8 02 00 00 00 00 00 00 | ................ | 0x0000000000000060 | d8 02 00 00 00 00 00 00 d8 02 00 00 00 00 00 00 | ................ | |
| 66 | +|0x0000000000000070 | 08 00 00 00 00 00 00 00 03 00 00 00 04 00 00 00 | ................ | 0x0000000000000070 | 08 00 00 00 00 00 00 00 03 00 00 00 04 00 00 00 | ................ | |
| 67 | +|0x0000000000000080 | 18 03 00 00 00 00 00 00 18 03 00 00 00 00 00 00 | ................ | 0x0000000000000080 | 18 03 00 00 00 00 00 00 18 03 00 00 00 00 00 00 | ................ | |
| 68 | +|0x0000000000000090 | 18 03 00 00 00 00 00 00 1c 00 00 00 00 00 00 00 | ................ | 0x0000000000000090 | 18 03 00 00 00 00 00 00 1c 00 00 00 00 00 00 00 | ................ | |
| 69 | +
|
| 70 | +... |
| 71 | +|0x00000000000002f0 | 30 9c 00 00 00 00 00 00 30 9c 00 00 00 00 00 00 | 0.......0....... | 0x00000000000002f0 | 30 9c 00 00 00 00 00 00 30 9c 00 00 00 00 00 00 | 0.......0....... | |
| 72 | +|0x0000000000000300 | d0 03 00 00 00 00 00 00 d0 03 00 00 00 00 00 00 | ................ | 0x0000000000000300 | d0 03 00 00 00 00 00 00 d0 03 00 00 00 00 00 00 | ................ | |
| 73 | +`------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------' |
| 74 | + 1 2 -/+0x320 | Z A file0 +/-1 | C D file1 +/-1 | G B end/begin | N M next/prev | \//\ +/-16 | < > +/-1 | : seek |
| 75 | +
|
| 76 | +``` |
| 77 | + |
| 78 | +`-S` mode allows you to adjust the window size of the hexadecimal view to your preference. |
| 79 | +Minimmum: `W = 120 H = 20` |
| 80 | + |
| 81 | +Example : `rz-diff -HS 120x20 /bin/true /bin/false` |
| 82 | + |
| 83 | +### File Type Based Diffing |
| 84 | + |
| 85 | +`t` option computes the difference between two files based on its type. |
| 86 | + |
| 87 | +``` |
| 88 | + -t --------> bytes (raw bytes in the files) |
| 89 | + |----> lines (compares text files) |
| 90 | + |----> functions (compares functions found in the files) |
| 91 | + |----> classes (compares classes found in the files) |
| 92 | + |----> command (compares command output returned when executed) |
| 93 | + |----> entries (compares entries found in the files) |
| 94 | + |----> fields (compares fields found in the files) |
| 95 | + |----> graphs (compares 2 functions and outputs in graphviz/dot format) |
| 96 | + |----> format (compares text files) |
| 97 | + |----> imports (compares imports found in the files) |
| 98 | + |----> libraries (compares libraries found in the files) |
| 99 | + |----> sections (compares sections found in the files) |
| 100 | + |----> strings (compares sections found in the files) |
| 101 | + |----> symbols (compares symbols found in the files) |
| 102 | +
|
| 103 | +``` |
| 104 | + |
| 105 | +### Diffing ASCII-text files: |
| 106 | + |
| 107 | +` $ rz-diff -t lines genuine cracked` |
6 | 108 | ``` |
7 | | -$ rz-diff genuine cracked |
8 | | -0x000081e0 85c00f94c0 => 9090909090 0x000081e0 |
9 | | -0x0007c805 85c00f84c0 => 9090909090 0x0007c805 |
| 109 | +--- genuine |
| 110 | ++++ cracked |
| 111 | +@@ -1,1 +1,1 @@ |
| 112 | +-hello1234567890 |
| 113 | ++1234567890hello |
| 114 | +``` |
| 115 | + |
| 116 | +### Diffing functions in binaries: |
| 117 | + |
| 118 | +It this mode, it will give you three columns for all functions: "First file offset", "Percentage of matching" and "Second file offset". |
| 119 | + |
| 120 | +` $ rz-diff -t functions /bin/true /bin/false` |
10 | 121 |
|
11 | | -$ rz-asm -d 85c00f94c0 |
12 | | -test eax, eax |
13 | | -sete al |
14 | 122 | ``` |
15 | | -Notice how the two jumps are nop'ed. |
| 123 | + sym.imp.__fprintf_chk 11 0x00000000000024e0 | MATCH (1.000000) | 0x00000000000024e0 11 sym.imp.__fprintf_chk |
| 124 | + sym.imp.mbsinit 11 0x00000000000024f0 | MATCH (1.000000) | 0x00000000000024f0 11 sym.imp.mbsinit |
| 125 | + sym.imp.iswprint 11 0x0000000000002500 | MATCH (1.000000) | 0x0000000000002500 11 sym.imp.iswprint |
| 126 | + sym.imp.__ctype_b_loc 11 0x0000000000002510 | MATCH (1.000000) | 0x0000000000002510 11 sym.imp.__ctype_b_loc |
| 127 | + fcn.00002640 34 0x0000000000002640 | UNMATCH (0.058824) | 0x0000000000002650 34 fcn.00002650 |
| 128 | + fcn.00002700 840 0x0000000000002700 | UNMATCH (0.221163) | 0x0000000000002710 840 fcn.00002710 |
| 129 | + fcn.00002b30 176 0x0000000000002b30 | UNMATCH (0.173077) | 0x0000000000002b40 176 fcn.00002b40 |
| 130 | + fcn.00002bf0 208 0x0000000000002bf0 | SIMILAR (0.961538) | 0x0000000000002c00 208 fcn.00002c00 |
| 131 | + fcn.00002cd0 4627 0x0000000000002cd0 | SIMILAR (0.993949) | 0x0000000000002ce0 4627 fcn.00002ce0 |
| 132 | +``` |
| 133 | + |
| 134 | +### Diffing classes in binaries: |
| 135 | + |
| 136 | +`rz-diff -t functions /bin/true /bin/false` |
16 | 137 |
|
17 | | -For bulk processing, you may want to have a higher-level overview of differences. This is why rizin is able to compute the distance and the percentage of similarity between two files with the `-s` option: |
18 | 138 | ``` |
19 | | -$ rz-diff -s /bin/true /bin/false |
20 | | -similarity: 0.97 |
21 | | -distance: 743 |
| 139 | +--- /bin/true |
| 140 | ++++ /bin/false |
22 | 141 | ``` |
23 | 142 |
|
24 | | -If you want more concrete data, it's also possible to count the differences, with the `-c` option: |
| 143 | +### Commands |
| 144 | + |
| 145 | + |
| 146 | +### Diffing entries in binaries |
| 147 | + |
| 148 | +`rz-diff -t entries /bin/true /bin/false` |
| 149 | + |
25 | 150 | ``` |
26 | | -$ rz-diff -c genuine cracked |
27 | | -2 |
| 151 | +--- /bin/true |
| 152 | ++++ /bin/false |
| 153 | +@@ -1,3 +1,3 @@ |
| 154 | +-virt: 0x00000000000026f0 phys: 0x00000000000026f0 entry init |
| 155 | +-virt: 0x00000000000026b0 phys: 0x00000000000026b0 entry fini |
| 156 | +-virt: 0x0000000000002610 phys: 0x0000000000002610 entry program |
| 157 | ++virt: 0x0000000000002700 phys: 0x0000000000002700 entry init |
| 158 | ++virt: 0x00000000000026c0 phys: 0x00000000000026c0 entry fini |
| 159 | ++virt: 0x0000000000002620 phys: 0x0000000000002620 entry program |
| 160 | +
|
28 | 161 | ``` |
29 | 162 |
|
30 | | -If you are unsure whether you are dealing with similar binaries, with `-C` flag you can check there are matching functions. It this mode, it will give you three columns for all functions: "First file offset", "Percentage of matching" and "Second file offset". |
| 163 | +### Diffing fields in binaries: |
| 164 | + |
| 165 | +`rz-diff -t fields /bin/true /bin/false ` |
31 | 166 |
|
32 | 167 | ``` |
33 | | -$ rz-diff -C /bin/false /bin/true |
34 | | - entry0 0x4013e8 | MATCH (0.904762) | 0x4013e2 entry0 |
35 | | - sym.imp.__libc_start_main 0x401190 | MATCH (1.000000) | 0x401190 sym.imp.__libc_start_main |
36 | | - fcn.00401196 0x401196 | MATCH (1.000000) | 0x401196 fcn.00401196 |
37 | | - fcn.0040103c 0x40103c | MATCH (1.000000) | 0x40103c fcn.0040103c |
38 | | - fcn.00401046 0x401046 | MATCH (1.000000) | 0x401046 fcn.00401046 |
39 | | - fcn.000045e0 24 0x45e0 | UNMATCH (0.916667) | 0x45f0 24 fcn.000045f0 |
40 | | - ... |
| 168 | +--- /bin/true |
| 169 | ++++ /bin/false |
41 | 170 | ``` |
42 | | -Moreover, we can ask rz-diff to perform analysis first - adding `-A` option will run `aaa` on the binaries. |
43 | | -And we can specify binaries architecture for this analysis too using |
| 171 | + |
| 172 | +### Diffing sections in binaries: |
| 173 | + |
| 174 | +`rz-diff -t sections /bin/true /bin/false` |
| 175 | + |
44 | 176 | ``` |
45 | | -$ rz-diff -AC -a x86 /bin/true /bin/false | grep UNMATCH |
46 | | -[x] Analyze all flags starting with sym. and entry0 (aa) |
47 | | -[x] Analyze len bytes of instructions for references (aar) |
48 | | -[x] Analyze function calls (aac) |
49 | | -[ ] [*] Use -AA or aaaa to perform additional experimental analysis. |
50 | | -[x] Constructing a function name for fcn.* and sym.func.* functions (aan)) |
51 | | -[x] Analyze all flags starting with sym. and entry0 (aa) |
52 | | -[x] Analyze len bytes of instructions for references (aar) |
53 | | -[x] Analyze function calls (aac) |
54 | | -[ ] [*] Use -AA or aaaa to perform additional experimental analysis. |
55 | | -[x] Constructing a function name for fcn.* and sym.func.* functions (aan)) |
56 | | - sub.fileno_500 86 0x4500 | UNMATCH (0.965116) | 0x4510 86 sub.fileno_510 |
57 | | - sub.__freading_4c0 59 0x44c0 | UNMATCH (0.949153) | 0x44d0 59 sub.__freading_4d0 |
58 | | - sub.fileno_440 120 0x4440 | UNMATCH (0.200000) | 0x4450 120 sub.fileno_450 |
59 | | - sub.setlocale_fa0 64 0x3fa0 | UNMATCH (0.104651) | 0x3fb0 64 sub.setlocale_fb0 |
60 | | - fcn.00003a50 120 0x3a50 | UNMATCH (0.125000) | 0x3a60 120 fcn.00003a60 |
| 177 | +
|
| 178 | +--- /bin/true |
| 179 | ++++ /bin/false |
61 | 180 | ``` |
62 | 181 |
|
63 | | -And now a cool feature : rizin supports graph-diffing, à la [DarunGrim](http://www.darungrim.org/), with the `-g` option. You can either give it a symbol name, of specify two offsets, if the function you want to diff is named differently in compared files. For example, `rz-diff -md -g main /bin/true /bin/false | xdot -` will show differences in `main()` function of Unix `true` and `false` programs. You can compare it to `rz-diff -md -g main /bin/false /bin/true | xdot -` (Notice the order of the arguments) to get the two versions. |
64 | | -This is the result: |
| 182 | +### Diffing strings in binaries: |
65 | 183 |
|
66 | | - |
| 184 | +`rz-diff -t strings /bin/true /bin/false` |
67 | 185 |
|
68 | | -Parts in yellow indicate that some offsets do not match. The grey piece means a perfect match. The orange one highlights a strong difference. If you look closely, you will see that the left part of the picture has `mov eax, 0x1; pop rbx; pop rbp; ret`, while the right one has `xor edx, edx; pop rbx; pop rbp; ret`. |
| 186 | +``` |
| 187 | +--- /bin/true |
| 188 | ++++ /bin/false |
| 189 | +@@ -11,7 +11,7 @@ |
| 190 | + Written by %s, %s, %s,\n%s, %s, %s, %s,\nand %s.\n |
| 191 | + Copyright %s %d Free Software Foundation, Inc. |
| 192 | + --help display this help and exit\n |
| 193 | +-Exit with a status code indicating success. |
| 194 | ++Exit with a status code indicating failure. |
| 195 | + Written by %s, %s, %s,\n%s, %s, %s, and %s.\n |
| 196 | + Written by %s, %s, %s,\n%s, %s, and %s.\n |
| 197 | + https://www.gnu.org/software/coreutils/ |
| 198 | +@@ -51,7 +51,7 @@ |
| 199 | + --help |
| 200 | + ASCII |
| 201 | + POSIX |
| 202 | ++false |
| 203 | + shell |
| 204 | + %s\n\n |
| 205 | + 8.30 |
| 206 | +-true |
69 | 207 |
|
70 | | -Binary diffing is an important feature for reverse engineering. It can be used to analyze [security updates](https://en.wikipedia.org/wiki/Patch_Tuesday), infected binaries, firmware changes and more... |
| 208 | +``` |
71 | 209 |
|
72 | | -We have only shown the code analysis diffing functionality, but rizin supports additional types of diffing between two binaries: at byte level, deltified similarities, and more to come. |
| 210 | +### Diffing symbols in binaries: |
73 | 211 |
|
74 | | -We have plans to implement more kinds of bindiffing algorithms into rizin, and why not, add support for ASCII art graph diffing and better integration with the rest of the toolkit. |
| 212 | +`rz-diff -t symbols /bin/true /bin/false` |
75 | 213 |
|
| 214 | +``` |
| 215 | +--- /bin/true |
| 216 | ++++ /bin/false |
| 217 | +``` |
0 commit comments