Ку, киберрекруты. Сегодня мы по-прежнему собираемся рассмотреть некоторые основные структуры данных, с которыми вы можете столкнуться во многих проектах. По моему опыту, ключевыми концепциями реверса являются идентификация структур данных, знание основных операций, а затем все зависит от конкретной проблемы, которую вы хотите решить. Если вы занимаетесь анализом вредоносного ПО, вам придется сосредоточиться на общих приемах вредоносного ПО, таких как использование определенных системных вызовов или методов упаковки/шифрования и т. д. Если вы занимаетесь разработкой эксплойтов, вы больше сосредоточитесь на конкретных протоколах, которые хотите анализировать и фаззить. Я также знаю некоторых людей, которые проводят анализ конфиденциальности приложений и больше внимания уделяют все, что связано с сетевыми протоколами. Знаете, любая конкретная область имеет свои особенности, и вы это поймете, но прежде чем углубляться в любую из них, вам понадобится прочная база по общим аспектам, таким как структуры данных, поскольку все построено на их основе.
В моем последнем посте мы рассмотрели некоторые базовые массивы (int и char), сегодня мы рассмотрим более сложные примеры.
Многомерные массивы
Даже название звучит довольно круто, это тоже очень простые структуры данных. Массив может содержать внутри любой элемент любого типа, у нас могут быть массивы целых чисел, массивы чисел с плавающей запятой, символов… и мы можем иметь массивы массивов. Кстати, у нас могут быть массивы массивов массивов […].
Давайте проверим следующий код:
C:
# include <stdio.h>
main(){
func();
getchar();
}
func(){
int marks[2][10] =
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
printf("Mark related to third student on first group %d",
marks[0][2]);
printf("Mark related to third student on second group %d",
marks[1][2]);
}
Как видите, мы объявляем двухмерный массив int и инициализируем его некоторыми значениями. Что интересно, мы инициализируем два массива один за другим! Может показаться, что у нас есть только один большой массив из 20 значений вместо двух массивов по 10 значений, один «поверх(?)» другого. Если подумать, это имеет смысл, есть ли другой способ сделать это? В конце концов, программе придется сохранить эти значения (два массива) в памяти, и они являются частью одной и той же «структуры», поэтому имеет смысл разместить их вместе одно за другим, так как если бы это было по-другому, это не помогло бы. Это не имеет большого смысла.
Код:
[0x55af6f3ae714]> pdf
/ (fcn) sym.func 230
| sym.func ();
| ; var int local_60h @ rbp-0x60
| ; var int local_5ch @ rbp-0x5c
| ; var int local_58h @ rbp-0x58
| ; var int local_54h @ rbp-0x54
| ; var int local_50h @ rbp-0x50
| ; var int local_4ch @ rbp-0x4c
| ; var int local_48h @ rbp-0x48
| ; var int local_44h @ rbp-0x44
| ; var int local_40h @ rbp-0x40
| ; var int local_3ch @ rbp-0x3c
| ; var int local_38h @ rbp-0x38
| ; var int local_34h @ rbp-0x34
| ; var int local_30h @ rbp-0x30
| ; var int local_2ch @ rbp-0x2c
| ; var int local_28h @ rbp-0x28
| ; var int local_24h @ rbp-0x24
| ; var int local_20h @ rbp-0x20
| ; var int local_1ch @ rbp-0x1c
| ; var int local_18h @ rbp-0x18
| ; var int local_14h @ rbp-0x14
| ; var int local_8h @ rbp-0x8
| ; CALL XREF from 0x55af6f3ae703 (sym.main)
| 0x55af6f3ae714 55 push rbp
| 0x55af6f3ae715 4889e5 mov rbp, rsp
| 0x55af6f3ae718 4883ec60 sub rsp, 0x60 ; '`'
| 0x55af6f3ae71c 64488b042528. mov rax, qword fs:[0x28] ; [0x28:8]=-1 ; '(' ; 40
| 0x55af6f3ae725 488945f8 mov qword [local_8h], rax
| 0x55af6f3ae729 31c0 xor eax, eax
| 0x55af6f3ae72b c745a0010000. mov dword [local_60h], 1
| 0x55af6f3ae732 c745a4020000. mov dword [local_5ch], 2
| 0x55af6f3ae739 c745a8030000. mov dword [local_58h], 3
| 0x55af6f3ae740 c745ac040000. mov dword [local_54h], 4
| 0x55af6f3ae747 c745b0050000. mov dword [local_50h], 5
| 0x55af6f3ae74e c745b4060000. mov dword [local_4ch], 6
| 0x55af6f3ae755 c745b8070000. mov dword [local_48h], 7
| 0x55af6f3ae75c c745bc080000. mov dword [local_44h], 8
| 0x55af6f3ae763 c745c0090000. mov dword [local_40h], 9
| 0x55af6f3ae76a c745c40a0000. mov dword [local_3ch], 0xa
| 0x55af6f3ae771 c745c80b0000. mov dword [local_38h], 0xb ; 11
| 0x55af6f3ae778 c745cc0c0000. mov dword [local_34h], 0xc ; 12
| 0x55af6f3ae77f c745d00d0000. mov dword [local_30h], 0xd ; 13
| 0x55af6f3ae786 c745d40e0000. mov dword [local_2ch], 0xe ; 14
| 0x55af6f3ae78d c745d80f0000. mov dword [local_28h], 0xf ; 15
| 0x55af6f3ae794 c745dc100000. mov dword [local_24h], 0x10 ; 16
| 0x55af6f3ae79b c745e0110000. mov dword [local_20h], 0x11 ; 17
| 0x55af6f3ae7a2 c745e4120000. mov dword [local_1ch], 0x12 ; 18
| 0x55af6f3ae7a9 c745e8130000. mov dword [local_18h], 0x13 ; 19
| 0x55af6f3ae7b0 c745ec140000. mov dword [local_14h], 0x14 ; 20
| 0x55af6f3ae7b7 8b45a8 mov eax, dword [local_58h]
| 0x55af6f3ae7ba 89c6 mov esi, eax
| 0x55af6f3ae7bc 488d3dc50000. lea rdi, qword str.Mark_related_to_third_student_on_first_group__d ; 0x55af6f3ae888 ; "Mark related to third student on first group %d"
| 0x55af6f3ae7c3 b800000000 mov eax, 0
| 0x55af6f3ae7c8 e8f3fdffff call sym.imp.printf ; int printf(const char *format)
| 0x55af6f3ae7cd 8b45d0 mov eax, dword [local_30h]
| 0x55af6f3ae7d0 89c6 mov esi, eax
| 0x55af6f3ae7d2 488d3ddf0000. lea rdi, qword str.Mark_related_to_third_student_on_second_group__d ; 0x55af6f3ae8b8 ; "Mark related to third student on second group %d"
| 0x55af6f3ae7d9 b800000000 mov eax, 0
| 0x55af6f3ae7de e8ddfdffff call sym.imp.printf ; int printf(const char *format)
| 0x55af6f3ae7e3 90 nop
| 0x55af6f3ae7e4 488b55f8 mov rdx, qword [local_8h]
| 0x55af6f3ae7e8 644833142528. xor rdx, qword fs:[0x28]
| ,=< 0x55af6f3ae7f1 7405 je 0x55af6f3ae7f8
| | 0x55af6f3ae7f3 e8b8fdffff call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
| `-> 0x55af6f3ae7f8 c9 leave
\ 0x55af6f3ae7f9 c3 ret
[0x55af6f3ae714]>
Какой беспорядок! Как вы можете заметить с первого взгляда, radare2 идентифицировал каждую ячейку нашего многомерного массива как независимую переменную, на самом деле код очень прост.
Код:
| 0x55af6f3ae72b c745a0010000. mov dword [local_60h], 1
| 0x55af6f3ae732 c745a4020000. mov dword [local_5ch], 2
| 0x55af6f3ae739 c745a8030000. mov dword [local_58h], 3
| 0x55af6f3ae740 c745ac040000. mov dword [local_54h], 4
| 0x55af6f3ae747 c745b0050000. mov dword [local_50h], 5
| 0x55af6f3ae74e c745b4060000. mov dword [local_4ch], 6
| 0x55af6f3ae755 c745b8070000. mov dword [local_48h], 7
| 0x55af6f3ae75c c745bc080000. mov dword [local_44h], 8
| 0x55af6f3ae763 c745c0090000. mov dword [local_40h], 9
| 0x55af6f3ae76a c745c40a0000. mov dword [local_3ch], 0xa
| 0x55af6f3ae771 c745c80b0000. mov dword [local_38h], 0xb ; 11
| 0x55af6f3ae778 c745cc0c0000. mov dword [local_34h], 0xc ; 12
| 0x55af6f3ae77f c745d00d0000. mov dword [local_30h], 0xd ; 13
| 0x55af6f3ae786 c745d40e0000. mov dword [local_2ch], 0xe ; 14
| 0x55af6f3ae78d c745d80f0000. mov dword [local_28h], 0xf ; 15
| 0x55af6f3ae794 c745dc100000. mov dword [local_24h], 0x10 ; 16
| 0x55af6f3ae79b c745e0110000. mov dword [local_20h], 0x11 ; 17
| 0x55af6f3ae7a2 c745e4120000. mov dword [local_1ch], 0x12 ; 18
| 0x55af6f3ae7a9 c745e8130000. mov dword [local_18h], 0x13 ; 19
| 0x55af6f3ae7b0 c745ec140000. mov dword [local_14h], 0x14 ; 2
Значения устанавливаются, а затем необходимые переменные передаются в
printf
, вот и все. Иногда вы можете столкнуться с подобными сценариями. Когда мы видим что-то подобное, мы можем захотеть избавиться от некоторых тегов useles local_whatever
. Мы знаем, что можем удалить любую мешающую переменную с помощью avf-
и сделать их красивее с помощью avfn
.
Код:
[0x55af6f3ae714]> afv- local_54h
[0x55af6f3ae714]> afv- local_58h
[0x55af6f3ae714]> afv- local_5ch
[0x55af6f3ae714]> afvn local_60h multiarray
[0x55af6f3ae714]> pdf
/ (fcn) sym.func 230
| sym.func ();
| ; var int multiarray @ rbp-0x60
| ; var int local_8h @ rbp-0x8
| ; CALL XREF from 0x55af6f3ae703 (sym.main)
| 0x55af6f3ae714 55 push rbp
| 0x55af6f3ae715 4889e5 mov rbp, rsp
| 0x55af6f3ae718 4883ec60 sub rsp, 0x60 ; '`'
| 0x55af6f3ae71c 64488b042528. mov rax, qword fs:[0x28] ; [0x28:8]=-1 ; '(' ; 40
| 0x55af6f3ae725 488945f8 mov qword [local_8h], rax
| 0x55af6f3ae729 31c0 xor eax, eax
| 0x55af6f3ae72b c745a0010000. mov dword [multiarray], 1
| 0x55af6f3ae732 c745a4020000. mov dword [rbp - 0x5c], 2
| 0x55af6f3ae739 c745a8030000. mov dword [rbp - 0x58], 3
| 0x55af6f3ae740 c745ac040000. mov dword [rbp - 0x54], 4
Когда мы имеем дело с массивом, в общих чертах нам просто нужно записать его базовый адрес, как если бы мы знали базовый адрес и размер, который мы можем получить к чему угодно, поэтому правильно обозначьте этот адрес и делайте свои заметки. Но как более эффективно проверять эти массивы? Команда
pf
в radare2 может помочь нам при проверке памяти:
Код:
[0x555e65e677b7]> afvd
var local_8h = 0x7ffdd66dcfb8 0x7a48b8b948f3ac00 ...H..Hz
var multiarray = 0x7ffdd66dcf60 0x0000000200000001 ........ @rsp
[0x555e65e677b7]> pf 20d val @ 0x7ffdd66dcf60
0x7ffdd66dcf60 [0] {
val : 0x7ffdd66dcf60 = 1
}
0x7ffdd66dcf64 [1] {
val : 0x7ffdd66dcf64 = 2
}
0x7ffdd66dcf68 [2] {
val : 0x7ffdd66dcf68 = 3
}
0x7ffdd66dcf6c [3] {
val : 0x7ffdd66dcf6c = 4
}
0x7ffdd66dcf70 [4] {
val : 0x7ffdd66dcf70 = 5
}
0x7ffdd66dcf74 [5] {
val : 0x7ffdd66dcf74 = 6
}
0x7ffdd66dcf78 [6] {
val : 0x7ffdd66dcf78 = 7
}
0x7ffdd66dcf7c [7] {
val : 0x7ffdd66dcf7c = 8
}
0x7ffdd66dcf80 [8] {
val : 0x7ffdd66dcf80 = 9
}
0x7ffdd66dcf84 [9] {
val : 0x7ffdd66dcf84 = 10
}
0x7ffdd66dcf88 [10] {
val : 0x7ffdd66dcf88 = 11
}
0x7ffdd66dcf8c [11] {
val : 0x7ffdd66dcf8c = 12
}
0x7ffdd66dcf90 [12] {
val : 0x7ffdd66dcf90 = 13
}
0x7ffdd66dcf94 [13] {
val : 0x7ffdd66dcf94 = 14
}
0x7ffdd66dcf98 [14] {
val : 0x7ffdd66dcf98 = 15
}
0x7ffdd66dcf9c [15] {
val : 0x7ffdd66dcf9c = 16
}
0x7ffdd66dcfa0 [16] {
val : 0x7ffdd66dcfa0 = 17
}
0x7ffdd66dcfa4 [17] {
val : 0x7ffdd66dcfa4 = 18
}
0x7ffdd66dcfa8 [18] {
val : 0x7ffdd66dcfa8 = 19
}
0x7ffdd66dcfac [19] {
val : 0x7ffdd66dcfac = 20
}
[0x555e65e677b7]>
Это было хорошо! Нам удалось получить 20 десятичных целых чисел со знаком, начиная с
0x7ffdd66dcf60
. После pf
мы используем 20d
, чтобы указать, что мы хотим получить 20 значений, используя строку формата %d
, начиная с этого адреса, мы можем использовать другие строки формата, такие как %c
для символов, %f
для чисел с плавающей запятой или %s
, %x
для шестнадцатеричных или для строки. Мы можем даже объединить строки формата в цепочку, используя что-то вроде 20iiis
, чтобы указать, что мы хотим представлять три целых числа и строку. Мы рассмотрим это более подробно в этом "курсе".Итак, вкратце, с этой точки зрения наличие массива массивов на практическом уровне почти то же самое, что наличие одного большого массива, поскольку все будет вместе, это больше похоже на семантический трюк, облегчающий жизнь нам, людям. работать со структурами данных при программировании.
Структуры
Но в большинстве случаев, особенно если мы имеем дело с более "серьёзными" проектами, мы можем ожидать встречи с более продвинутыми структурами данных, которые могут быть связаны с объектами. В конце концов, эти структуры будут состоять из наборов массивов, тегов адресов памяти и простых переменных. Это одна из причин, почему я люблю работать на низком уровне: все становится очень просто.
В таких языках, как C, мы можем определять более сложные структуры данных, используя struct. Иногда нам может потребоваться уникальная ссылка на набор данных, относящихся к определенной теме вашей программы, например, вы можете захотеть сохранить координаты одной географической точки или, возможно, сохранить данные объекта с его имя и итоговые оценки учеников или что-то еще, что вам нужно сделать, вы поняли концепцию. Для этого в C используется Struct, как вы можете видеть в следующем коде:
C:
#include <stdio.h>
#include <stdlib.h>
struct students {
int a[20];
char b[20];
};
int main( ) {
time_t t;
int i, n;
srand((unsigned) time(&t));
struct students s1;
for( i = 0 ; i < 20 ; i++ ) {
s1.a[i] = rand() % 11;
}
for( i = 0 ; i < 20 ; i++ ) {
printf("%d ",s1.a[i]);
}
return 0;
}
Как вы можете видеть, определена структура студентов, состоящая из массива int и массива символов, затем она далее инициализируется в коде. Также обратите внимание, что на этот раз мы используем другую библиотеку, stdlib и rand. Давайте проверим это:
Код:
[0x7efc2890e090]> ii
[Imports]
1 0x55d00da94000 WEAK NOTYPE _ITM_deregisterTMCloneTable
2 0x55d00da94610 GLOBAL FUNC __stack_chk_fail
3 0x55d00da94620 GLOBAL FUNC printf
4 0x55d00da94000 GLOBAL FUNC __libc_start_main
5 0x55d00da94630 GLOBAL FUNC srand
6 0x55d00da94000 WEAK NOTYPE __gmon_start__
7 0x55d00da94640 GLOBAL FUNC time
8 0x55d00da94000 WEAK NOTYPE _ITM_registerTMCloneTable
9 0x55d00da94000 WEAK FUNC __cxa_finalize
10 0x55d00da94650 GLOBAL FUNC rand
1 0x55d00da94000 WEAK NOTYPE _ITM_deregisterTMCloneTable
4 0x55d00da94000 GLOBAL FUNC __libc_start_main
6 0x55d00da94000 WEAK NOTYPE __gmon_start__
8 0x55d00da94000 WEAK NOTYPE _ITM_registerTMCloneTable
9 0x55d00da94000 WEAK FUNC __cxa_finalize
На первый взгляд, изучив этот импорт, мы уже знаем, что эта программа работает со случайными числами. На этот раз блок кода, который мы хотим проанализировать, находится в функции main:
Код:
[0x55d00da9477a]> pdf
;-- main:
/ (fcn) main 189
| main ();
| ; var int local_7ch @ rbp-0x7c
| ; var int local_78h @ rbp-0x78
| ; var int local_8h @ rbp-0x8
| ; DATA XREF from 0x55d00da9468d (entry0)
| 0x55d00da9477a 55 push rbp
| 0x55d00da9477b 4889e5 mov rbp, rsp
| 0x55d00da9477e 4883c480 add rsp, -0x80
| 0x55d00da94782 64488b042528. mov rax, qword fs:[0x28] ; [0x28:8]=-1 ; '(' ; 40
| 0x55d00da9478b 488945f8 mov qword [local_8h], rax
| 0x55d00da9478f 31c0 xor eax, eax
| 0x55d00da94791 488d4588 lea rax, qword [local_78h]
| 0x55d00da94795 4889c7 mov rdi, rax
| 0x55d00da94798 b800000000 mov eax, 0
| 0x55d00da9479d e89efeffff call sym.imp.time ; time_t time(time_t *timer)
| 0x55d00da947a2 89c7 mov edi, eax
| 0x55d00da947a4 e887feffff call sym.imp.srand ; void srand(int seed)
| 0x55d00da947a9 c74584000000. mov dword [local_7ch], 0
| ,=< 0x55d00da947b0 eb35 jmp 0x55d00da947e7
| .--> 0x55d00da947b2 e899feffff call sym.imp.rand ; int rand(void)
| :| 0x55d00da947b7 89c1 mov ecx, eax
| :| 0x55d00da947b9 bae9a28b2e mov edx, 0x2e8ba2e9
| :| 0x55d00da947be 89c8 mov eax, ecx
| :| 0x55d00da947c0 f7ea imul edx
| :| 0x55d00da947c2 d1fa sar edx, 1
| :| 0x55d00da947c4 89c8 mov eax, ecx
| :| 0x55d00da947c6 c1f81f sar eax, 0x1f
| :| 0x55d00da947c9 29c2 sub edx, eax
| :| 0x55d00da947cb 89d0 mov eax, edx
| :| 0x55d00da947cd c1e002 shl eax, 2
| :| 0x55d00da947d0 01d0 add eax, edx
| :| 0x55d00da947d2 01c0 add eax, eax
| :| 0x55d00da947d4 01d0 add eax, edx
| :| 0x55d00da947d6 29c1 sub ecx, eax
| :| 0x55d00da947d8 89ca mov edx, ecx
| :| 0x55d00da947da 8b4584 mov eax, dword [local_7ch]
| :| 0x55d00da947dd 4898 cdqe
| :| 0x55d00da947df 89548590 mov dword [rbp + rax*4 - 0x70], edx
| :| 0x55d00da947e3 83458401 add dword [local_7ch], 1
| :| ; JMP XREF from 0x55d00da947b0 (main)
| :`-> 0x55d00da947e7 837d8413 cmp dword [local_7ch], 0x13 ; [0x13:4]=-1 ; 19
| `==< 0x55d00da947eb 7ec5 jle 0x55d00da947b2
| 0x55d00da947ed c74584000000. mov dword [local_7ch], 0
| ,=< 0x55d00da947f4 eb20 jmp 0x55d00da94816
| .--> 0x55d00da947f6 8b4584 mov eax, dword [local_7ch]
| :| 0x55d00da947f9 4898 cdqe
| :| 0x55d00da947fb 8b448590 mov eax, dword [rbp + rax*4 - 0x70]
| :| 0x55d00da947ff 89c6 mov esi, eax
| :| 0x55d00da94801 488d3dbc0000. lea rdi, qword [0x55d00da948c4] ; "%d "
| :| 0x55d00da94808 b800000000 mov eax, 0
| :| 0x55d00da9480d e80efeffff call sym.imp.printf ; int printf(const char *format)
| :| 0x55d00da94812 83458401 add dword [local_7ch], 1
| :| ; JMP XREF from 0x55d00da947f4 (main)
| :`-> 0x55d00da94816 837d8413 cmp dword [local_7ch], 0x13 ; [0x13:4]=-1 ; 19
| `==< 0x55d00da9481a 7eda jle 0x55d00da947f6
| 0x55d00da9481c b800000000 mov eax, 0
| 0x55d00da94821 488b75f8 mov rsi, qword [local_8h]
| 0x55d00da94825 644833342528. xor rsi, qword fs:[0x28]
| ,=< 0x55d00da9482e 7405 je 0x55d00da94835
| | 0x55d00da94830 e8dbfdffff call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
| `-> 0x55d00da94835 c9 leave
\ 0x55d00da94836 c3 ret
[0x55d00da9477a]>
Блок здесь может показаться больше, чем предыдущие, но пусть это вас не пугает. На первый взгляд мы можем обнаружить пару циклов: первый, вероятно, инициализирует массив, а второй наверняка печатает его значения одно за другим, поскольку мы видим вызов printf.
Кстати, мы можем даже отметить это на разборке, чтобы лучше все осмотреть. С помощью комментария CCu @addr мы можем добавить комментарий, который будет отображаться рядом с определенным адресом памяти.
Код:
[0x55d00da9477a]> CCu "print array" @ 0x55d00da947f4
| 0x55d00da947ed c74584000000. mov dword [local_7ch], 0
| ,=< 0x55d00da947f4 eb20 jmp 0x55d00da94816 ; "print array"
| .--> 0x55d00da947f6 8b4584 mov eax, dword [local_7ch]
| :| 0x55d00da947f9 4898 cdqe
| :| 0x55d00da947fb 8b448590 mov eax, dword [rbp + rax*4 - 0x70]
| :| 0x55d00da947ff 89c6 mov esi, eax
| :| 0x55d00da94801 488d3dbc0000. lea rdi, qword [0x55d00da948c4] ; "%d "
Мы также можем легко перечислить все комментарии с помощью
Код:
[0x55d00da9477a]> CC
0x00000000 CCu "[28] ----- section size 254 named .shstrtab"
0x55d00da94000 CCu "[38] m-rw- section size 64 named ehdr"
0x55d00da94040 CCu "[29] m-r-- section size 504 named PHDR"
0x55d00da94238 CCu "[30] m-r-- section size 28 named INTERP"
0x55d00da94254 CCu "[34] m-r-- section size 68 named NOTE"
0x55d00da94274 CCu "[03] --r-- section size 36 named .note.gnu.build_id"
0x55d00da94298 CCu "[04] --r-- section size 28 named .gnu.hash"
0x55d00da942b8 CCu "[05] --r-- section size 264 named .dynsym"
0x55d00da943c0 CCu "[06] --r-- section size 170 named .dynstr"
0x55d00da9446a CCu "[07] --r-- section size 22 named .gnu.version"
0x55d00da94480 CCu "[08] --r-- section size 48 named .gnu.version_r"
0x55d00da944b0 CCu "[09] --r-- section size 192 named .rela.dyn"
0x55d00da94570 CCu "[10] --r-- section size 120 named .rela.plt"
0x55d00da945e8 CCu "[11] --r-x section size 23 named .init"
0x55d00da94600 CCu "[12] --r-x section size 96 named .plt"
0x55d00da94660 CCu "[13] --r-x section size 8 named .plt.got"
0x55d00da94670 CCu "[14] --r-x section size 578 named .text"
0x55d00da947f4 CCu "\"print array\""
0x55d00da948b4 CCu "[15] --r-x section size 9 named .fini"
0x55d00da948c0 CCu "[16] --r-- section size 8 named .rodata"
0x55d00da948c8 CCu "[35] m-r-- section size 60 named GNU_EH_FRAME"
0x55d00da94908 CCu "[18] --r-- section size 264 named .eh_frame"
0x55d00dc94d98 CCu "[37] m-r-- section size 616 named GNU_RELRO"
0x55d00dc94da0 CCu "[20] --rw- section size 8 named .fini_array"
0x55d00dc94da8 CCu "[33] m-rw- section size 496 named DYNAMIC"
0x55d00dc94f98 CCu "[22] --rw- section size 104 named .got"
0x55d00dc95000 CCu "[23] --rw- section size 16 named .data"
0x55d00dc95010 CCu "[24] --rw- section size 0 named .bss"
Теперь перейдем к первому циклу:
Код:
[0x55d00da9477a]> pdf
;-- main:
/ (fcn) main 189
| main ();
| ; var int local_7ch @ rbp-0x7c
| ; var int local_78h @ rbp-0x78
| ; var int local_8h @ rbp-0x8
| ; DATA XREF from 0x55d00da9468d (entry0)
На этот раз программа устанавливает три переменные: защиту стека и пару переменных: local_7ch, используемый для хранения i (счетчик цикла), а затем у нас есть local_78h, который, похоже, связан с вызовом tim.
Давайте посмотрим на это поближе:
Код:
| 0x55d00da94791 488d4588 lea rax, qword [local_78h]
| 0x55d00da94795 4889c7 mov rdi, rax
| 0x55d00da94798 b800000000 mov eax, 0
| 0x55d00da9479d e89efeffff call sym.imp.time ; time_t time(time_t *timer)
| 0x55d00da947a2 89c7 mov edi, eax
| 0x55d00da947a4 e887feffff call sym.imp.srand ; void srand(int seed)
| 0x55d00da947a9 c74584000000. mov dword [local_7ch], 0
Как видите, адрес памяти local_78h передается в time() в качестве параметра. Затем результат вызова (сохраненный в eax) снова передается в srand в качестве начального числа, после чего инициализируется первый счетчик цикла (i=0). Функция времени работает следующим образом: time_t time( time_t *секунда) функция времени принимает один параметр: секунду. Этот параметр используется для установки объекта time_t, который хранит время (
Ссылка скрыта от гостей
). И возвращает текущее время календаря как объект типа time_t. Функция srand означает начальное значение rand (?). Я думаю, и она используется для установки начального числа генератора случайных чисел, который будет использоваться функцией rand(). Генератору случайных чисел, используемому rand(), требуется начальное число, поскольку вы можете себе представить, что он вычисляет случайное число, используя математическую формулу (и, следовательно, ему нужны входные данные). Важно отметить, что использование одного и того же начального числа приведет к тому же результату в дальнейшем в коде.Что касается кода, как вы можете видеть, выходные данные функции времени передаются в srand, время часто используется в качестве случайного начального числа, потому что это одно из самых случайных значений, которые мы можем иметь внутри нашей машины, другие вещи, такие как также используется положение мыши или случайный набор слов, более сложные системы, такие как те, которые используются в банковском деле, могут даже использовать датчики температуры/давления и так далее.
Итак, теперь, когда srand установлен, программа сможет генерировать хорошие случайные числа, вызывая функцию rand. Когда наша функция rand готова, мы углубимся в первый цикл:
Код:
| 0x55d00da947a2 89c7 mov edi, eax
| 0x55d00da947a4 e887feffff call sym.imp.srand ; void srand(int seed)
| 0x55d00da947a9 c74584000000. mov dword [local_7ch], 0
| ,=< 0x55d00da947b0 eb35 jmp 0x55d00da947e7
| .--> 0x55d00da947b2 e899feffff call sym.imp.rand ; int rand(void)
| :| 0x55d00da947b7 89c1 mov ecx, eax
| :| 0x55d00da947b9 bae9a28b2e mov edx, 0x2e8ba2e9
| :| 0x55d00da947be 89c8 mov eax, ecx
| :| 0x55d00da947c0 f7ea imul edx
| :| 0x55d00da947c2 d1fa sar edx, 1
| :| 0x55d00da947c4 89c8 mov eax, ecx
| :| 0x55d00da947c6 c1f81f sar eax, 0x1f
| :| 0x55d00da947c9 29c2 sub edx, eax
| :| 0x55d00da947cb 89d0 mov eax, edx
| :| 0x55d00da947cd c1e002 shl eax, 2
| :| 0x55d00da947d0 01d0 add eax, edx
| :| 0x55d00da947d2 01c0 add eax, eax
| :| 0x55d00da947d4 01d0 add eax, edx
| :| 0x55d00da947d6 29c1 sub ecx, eax
| :| 0x55d00da947d8 89ca mov edx, ecx
| :| 0x55d00da947da 8b4584 mov eax, dword [local_7ch]
| :| 0x55d00da947dd 4898 cdqe
| :| 0x55d00da947df 89548590 mov dword [rbp + rax*4 - 0x70], edx
| :| 0x55d00da947e3 83458401 add dword [local_7ch], 1
Для анализа этого блока самая фундаментальная часть должна иметь следующее: s1.a = rand() % 11; очень присутствует. Мы можем разбить его на три части (как вы уже знаете): сначала мы генерируем случайное число, затем выполняем % 11, затем сохраняем результат внутри s1.a. Итак, первая часть очень ясна:
Код:
| .--> 0x55d00da947b2 e899feffff call sym.imp.rand ; int rand(void)
| :| 0x55d00da947b7 89c1 mov ecx, eax
С помощью rand мы получаем случайное число (eax), затем сохраняем его в ecx, поскольку будем с ним работать. Следующая часть должна быть % 10, посмотрим;
Код:
| :| 0x55d00da947b9 bae9a28b2e mov edx, 0x2e8ba2e9
| :| 0x55d00da947be 89c8 mov eax, ecx
| :| 0x55d00da947c0 f7ea imul edx
| :| 0x55d00da947c2 d1fa sar edx, 1
| :| 0x55d00da947c4 89c8 mov eax, ecx
| :| 0x55d00da947c6 c1f81f sar eax, 0x1f
| :| 0x55d00da947c9 29c2 sub edx, eax
| :| 0x55d00da947cb 89d0 mov eax, edx
| :| 0x55d00da947cd c1e002 shl eax, 2
| :| 0x55d00da947d0 01d0 add eax, edx
| :| 0x55d00da947d2 01c0 add eax, eax
| :| 0x55d00da947d4 01d0 add eax, edx
| :| 0x55d00da947d6 29c1 sub ecx, eax| :| 0x55d00da947b9 bae9a28b2e mov edx, 0x2e8ba2e9
| :| 0x55d00da947be 89c8 mov eax, ecx
| :| 0x55d00da947c0 f7ea imul edx
| :| 0x55d00da947c2 d1fa sar edx, 1
| :| 0x55d00da947c4 89c8 mov eax, ecx
| :| 0x55d00da947c6 c1f81f sar eax, 0x1f
| :| 0x55d00da947c9 29c2 sub edx, eax
| :| 0x55d00da947cb 89d0 mov eax, edx
| :| 0x55d00da947cd c1e002 shl eax, 2
| :| 0x55d00da947d0 01d0 add eax, edx
| :| 0x55d00da947d2 01c0 add eax, eax
| :| 0x55d00da947d4 01d0 add eax, edx
| :| 0x55d00da947d6 29c1 sub ecx, eax
Когда мы имеем дело со «сложными» ситуациями, «мы не понимаем», подобными этой, у нас есть как минимум несколько вариантов. Первый вариант - получить общее представление о том, что происходит в блоке кода, и продолжить просмотр общей картины. Мы можем попытаться установить пару точек останова до и после того, как мы попадем в блок кода, посмотреть, как значение зайди и посмотри на результат.
С другой стороны, мы можем проверять функцию шаг за шагом, отслеживая входные данные и устанавливая точки останова при каждом изменении значения. Будьте осторожны, если вы выбрали этот вариант, поскольку некоторые функции (например, вызовы Win API, системные вызовы, большие проекты и т. д.) могут быть огромными, и вы, вероятно, потеряете много времени.
Код:
| :| 0x55d00da947be b 89c8 mov eax, ecx
| :| 0x55d00da947c0 f7ea imul edx
| :| 0x55d00da947c2 b d1fa sar edx, 1
| :| 0x55d00da947c4 b 89c8 mov eax, ecx
| :| 0x55d00da947c6 c1f81f sar eax, 0x1f
| :| 0x55d00da947c9 b 29c2 sub edx, eax
| :| 0x55d00da947cb 89d0 mov eax, edx
| :| 0x55d00da947cd c1e002 shl eax, 2
| :| 0x55d00da947d0 b 01d0 add eax, edx
| :| 0x55d00da947d2 b 01c0 add eax, eax
| :| 0x55d00da947d4 b 01d0 add eax, edx
| :| 0x55d00da947d6 29c1 sub ecx, eax
| :| 0x55d00da947d8 89ca mov edx, ecx
Код:
| .--> 0x555600e8b7b2 e899feffff call sym.imp.rand ; int rand(void)
| :| 0x555600e8b7b7 89c1 mov ecx, eax
| :| 0x555600e8b7b9 bae9a28b2e mov edx, 0x2e8ba2e9 ; rdx
[0x555600e8b7be]> dr eax
0x591fb69a
[0x555600e8b7be]> dr edx
0x2e8ba2e9
| :| 0x555600e8b7be b 89c8 mov eax, ecx
| :| 0x555600e8b7c0 f7ea imul edx
[0x555600e8b7be]> dr edx
0x10344fbf
| :| 0x555600e8b7c4 89c8 mov eax, ecx
| :| 0x555600e8b7c6 c1f81f sar eax, 0x1f
| :| ;-- rip:
[0x555600e8b7be]> dr eax
0x00000000
[0x555600e8b7be]> dr edx
0x081a27df
| :| 0x555600e8b7c9 b 29c2 sub edx, eax
| :| 0x555600e8b7cb 89d0 mov eax, edx
| :| 0x555600e8b7cd c1e002 shl eax, 2
[0x555600e8b7be]> dr eax
0x20689f7c
[0x555600e8b7be]> dr edx
0x081a27df
[0x555600e8b7be]>
[...]
[0x555600e8b7be]> dr
rax = 0x591fb695
rbx = 0x00000000
rcx = 0x00000005
Конечный результат — 0x5 -> декабрь 5, поэтому сгенерированное случайное число % 10 равно 5. Обратите внимание, что функция rand() возвращает число от 0x0 до 0xFFFFFFFFFFFFFFFF (18446744073709551615) на машине x64, а затем модуль используется для «обрезания» и установки максимального значения 50. Как вы можете видеть в этом случае, rand вернул: 0x591fb69a (1495250586), тогда некоторые операции, такие как выравнивание сдвига и умножение, сокращают это до того, что относительно 10.
Если вы хотите углубиться в эту тему, я предлагаю вам прочитать обсуждение здесь:
Ссылка скрыта от гостей
Также обратите внимание, что операцию мода можно выполнить разными способами! Есть способы, которые выглядели бы намного понятнее, чем использованный здесь, но компилятор не будет думать о том, насколько хорошо это будет выглядеть, компилятор попытается максимизировать производительность, а иногда использование определенного набора инструкций может привести к более быстрому результату. выполнение в этом контексте.
Итак, после этого мы видим, что значение сохраняется в массиве так же, как мы видели раньше:
Код:
| :| 0x555600e8b7da 8b4584 mov eax, dword [local_7ch]
| :| 0x555600e8b7dd 4898 cdqe
| :| 0x555600e8b7df 89548590 mov dword [rbp + rax*4 - 0x70], edx
| :| 0x555600e8b7e3 83458401 add dword [local_7ch], 1
| :| ; JMP XREF from 0x555600e8b7b0 (main)
| :`-> 0x555600e8b7e7 837d8413 cmp dword [local_7ch], 0x13 ; [0x13:4]=-1 ; 19
| `==< 0x555600e8b7eb 7ec5 jle 0x555600e8b7b2
И цикл повторяется 20 раз. На этом этапе, когда мы имеем дело со сложными структурами данных, которые содержат или могут содержать соответствующую информацию, оказывается очень полезным держать их в курсе. У нас может быть общее представление о том, как они структурированы, или у нас может быть дополнительная информация, например файл .h или что-то в этом роде. В Radare2 можно «сопоставить» определение структуры с конкретным адресом памяти, используя td и tl. Поскольку мы уже знаем о коде, давайте установим эту структуру в r2 и отобразим ее:
Код:
"td struct students {int a[20]; char b[20];}"
tl students = 0x7FFD69D8C94C
Таким образом, мы можем сопоставить эту структуру с адресом, который мы видим, проверив адрес, который, по нашему мнению, может соответствовать начальному значению, например, инициализируемого массива, а затем нажать dc и посмотреть, как программа обновляет (устанавливает) эти значения массива:
Код:
[0x555600e8b7be]> dc
hit breakpoint at: 555600e8b7be
[0x555600e8b7be]> tl
(students)
a : 0x7ffd69d8c94c = [ 0, 5, 8, 5, 3, 1, 6, 9, 2, 5, 8, 9, 2, 4, 7, 10, 3, 6, 6, 0 ]
b : 0x7ffd69d8c99c =
При этом важно отметить, что на самом деле мы можем ошибаться во многих отношениях (как в жизни), мы можем пропустить базовый адрес и определить неправильную структуру, мы должны использовать структуру, которая лучше всего подходит для нашего анализа.
Давайте теперь закончим это последним примером:
C:
#include <stdio.h>
#include <string.h>[/I][/I]
[I][I]struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
};[/I][/I]
[I][I]int main( ) {
struct Books Book1; /* Declare Book1 of type Book */
struct Books Book2; /* Declare Book2 of type Book */[/I][/I]
[I][I] /* book 1 specification */
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/* book 2 specification */
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;[/I][/I]
[I][I] /* print Book1 info */
printf( "Book 1 title : %s\n", Book1.title);
printf( "Book 1 author : %s\n", Book1.author);
printf( "Book 1 subject : %s\n", Book1.subject);
printf( "Book 1 book_id : %d\n", Book1.book_id);
/* print Book2 info */
printf( "Book 2 title : %s\n", Book2.title);
printf( "Book 2 author : %s\n", Book2.author);
printf( "Book 2 subject : %s\n", Book2.subject);
printf( "Book 2 book_id : %d\n", Book2.book_id);
return 0;
}
А дисасма выглядит так:
Код:
[0x56315b93e6aa]> pdf
;-- main:
/ (fcn) sym.main 529
| sym.main ();
| ; var int local_1b0h @ rbp-0x1b0
| ; var int local_e8h @ rbp-0xe8
| ; var int local_e0h @ rbp-0xe0
| ; var int local_18h @ rbp-0x18
| ; var int local_8h @ rbp-0x8
| ; DATA XREF from 0x56315b93e5bd (entry0)
| 0x56315b93e6aa 55 push rbp
| 0x56315b93e6ab 4889e5 mov rbp, rsp
| 0x56315b93e6ae 4881ecb00100. sub rsp, 0x1b0
| 0x56315b93e6b5 64488b042528. mov rax, qword fs:[0x28] ; [0x28:8]=-1 ; '(' ; 40
| 0x56315b93e6be 488945f8 mov qword [local_8h], rax
| 0x56315b93e6c2 31c0 xor eax, eax
| 0x56315b93e6c4 488d8550feff. lea rax, qword [local_1b0h]
| 0x56315b93e6cb 48ba43205072. movabs rdx, 0x6172676f72502043
| 0x56315b93e6d5 488910 mov qword [rax], rdx
| 0x56315b93e6d8 c740086d6d69. mov dword [rax + 8], 0x6e696d6d ; [0x6e696d6d:4]=-1
| 0x56315b93e6df 66c7400c6700 mov word [rax + 0xc], 0x67 ; 'g' ; [0x67:2]=0xffff ; 103
| 0x56315b93e6e5 488d8550feff. lea rax, qword [local_1b0h]
| 0x56315b93e6ec 4883c032 add rax, 0x32 ; '2'
| 0x56315b93e6f0 48b94e756861. movabs rcx, 0x696c41206168754e
| 0x56315b93e6fa 488908 mov qword [rax], rcx
| 0x56315b93e6fd c6400800 mov byte [rax + 8], 0
| 0x56315b93e701 488d8550feff. lea rax, qword [local_1b0h]
| 0x56315b93e708 4883c064 add rax, 0x64 ; 'd'
| 0x56315b93e70c 48ba43205072. movabs rdx, 0x6172676f72502043
| 0x56315b93e716 48b96d6d696e. movabs rcx, 0x755420676e696d6d
| 0x56315b93e720 488910 mov qword [rax], rdx
| 0x56315b93e723 48894808 mov qword [rax + 8], rcx
| 0x56315b93e727 c74010746f72. mov dword [rax + 0x10], 0x69726f74 ; [0x69726f74:4]=-1
| 0x56315b93e72e 66c74014616c mov word [rax + 0x14], 0x6c61 ; [0x6c61:2]=0xffff
| 0x56315b93e734 c6401600 mov byte [rax + 0x16], 0
| 0x56315b93e738 c78518ffffff. mov dword [local_e8h], 0x631caf
| 0x56315b93e742 488d8520ffff. lea rax, qword [local_e0h]
| 0x56315b93e749 48ba54656c65. movabs rdx, 0x206d6f63656c6554
| 0x56315b93e753 48b942696c6c. movabs rcx, 0x676e696c6c6942
| 0x56315b93e75d 488910 mov qword [rax], rdx
| 0x56315b93e760 48894808 mov qword [rax + 8], rcx
| 0x56315b93e764 488d8520ffff. lea rax, qword [local_e0h]
| 0x56315b93e76b 4883c032 add rax, 0x32 ; '2'
| 0x56315b93e76f 48ba5a617261. movabs rdx, 0x696c41206172615a
| 0x56315b93e779 488910 mov qword [rax], rdx
| 0x56315b93e77c c6400800 mov byte [rax + 8], 0
| 0x56315b93e780 488d8520ffff. lea rax, qword [local_e0h]
| 0x56315b93e787 4883c064 add rax, 0x64 ; 'd'
| 0x56315b93e78b 48ba54656c65. movabs rdx, 0x206d6f63656c6554
| 0x56315b93e795 48b942696c6c. movabs rcx, 0x20676e696c6c6942
| 0x56315b93e79f 488910 mov qword [rax], rdx
| 0x56315b93e7a2 48894808 mov qword [rax + 8], rcx
| 0x56315b93e7a6 48b95475746f. movabs rcx, 0x6c6169726f747554
| 0x56315b93e7b0 48894810 mov qword [rax + 0x10], rcx
| 0x56315b93e7b4 c6401800 mov byte [rax + 0x18], 0
| 0x56315b93e7b8 c745e8d41d63. mov dword [local_18h], 0x631dd4
| 0x56315b93e7bf 488d8550feff. lea rax, qword [local_1b0h]
| 0x56315b93e7c6 4889c6 mov rsi, rax
| 0x56315b93e7c9 488d3d740100. lea rdi, qword str.Book_1_title_:__s ; 0x56315b93e944 ; "Book 1 title : %s\n"
| 0x56315b93e7d0 b800000000 mov eax, 0
| 0x56315b93e7d5 e8a6fdffff call sym.imp.printf ; int printf(const char *format)
| 0x56315b93e7da 488d8550feff. lea rax, qword [local_1b0h]
| 0x56315b93e7e1 4883c032 add rax, 0x32 ; '2'
| 0x56315b93e7e5 4889c6 mov rsi, rax
| 0x56315b93e7e8 488d3d680100. lea rdi, qword str.Book_1_author_:__s ; 0x56315b93e957 ; "Book 1 author : %s\n"
| 0x56315b93e7ef b800000000 mov eax, 0
| 0x56315b93e7f4 e887fdffff call sym.imp.printf ; int printf(const char *format)
| 0x56315b93e7f9 488d8550feff. lea rax, qword [local_1b0h]
| 0x56315b93e800 4883c064 add rax, 0x64 ; 'd'
| 0x56315b93e804 4889c6 mov rsi, rax
| 0x56315b93e807 488d3d5d0100. lea rdi, qword str.Book_1_subject_:__s ; 0x56315b93e96b ; "Book 1 subject : %s\n"
| 0x56315b93e80e b800000000 mov eax, 0
| 0x56315b93e813 e868fdffff call sym.imp.printf ; int printf(const char *format)
| 0x56315b93e818 8b8518ffffff mov eax, dword [local_e8h]
| 0x56315b93e81e 89c6 mov esi, eax
| 0x56315b93e820 488d3d590100. lea rdi, qword str.Book_1_book_id_:__d ; 0x56315b93e980 ; "Book 1 book_id : %d\n"
| 0x56315b93e827 b800000000 mov eax, 0
| 0x56315b93e82c e84ffdffff call sym.imp.printf ; int printf(const char *format)
| 0x56315b93e831 488d8520ffff. lea rax, qword [local_e0h]
| 0x56315b93e838 4889c6 mov rsi, rax
| 0x56315b93e83b 488d3d530100. lea rdi, qword str.Book_2_title_:__s ; 0x56315b93e995 ; "Book 2 title : %s\n"
| 0x56315b93e842 b800000000 mov eax, 0
| 0x56315b93e847 e834fdffff call sym.imp.printf ; int printf(const char *format)
| 0x56315b93e84c 488d8520ffff. lea rax, qword [local_e0h]
| 0x56315b93e853 4883c032 add rax, 0x32 ; '2'
| 0x56315b93e857 4889c6 mov rsi, rax
| 0x56315b93e85a 488d3d470100. lea rdi, qword str.Book_2_author_:__s ; 0x56315b93e9a8 ; "Book 2 author : %s\n"
| 0x56315b93e861 b800000000 mov eax, 0
| 0x56315b93e866 e815fdffff call sym.imp.printf ; int printf(const char *format)
| 0x56315b93e86b 488d8520ffff. lea rax, qword [local_e0h]
| 0x56315b93e872 4883c064 add rax, 0x64 ; 'd'
| 0x56315b93e876 4889c6 mov rsi, rax
| 0x56315b93e879 488d3d3c0100. lea rdi, qword str.Book_2_subject_:__s ; 0x56315b93e9bc ; "Book 2 subject : %s\n"
| 0x56315b93e880 b800000000 mov eax, 0
| 0x56315b93e885 e8f6fcffff call sym.imp.printf ; int printf(const char *format)
| 0x56315b93e88a 8b45e8 mov eax, dword [local_18h]
| 0x56315b93e88d 89c6 mov esi, eax
| 0x56315b93e88f 488d3d3b0100. lea rdi, qword str.Book_2_book_id_:__d ; 0x56315b93e9d1 ; "Book 2 book_id : %d\n"
| 0x56315b93e896 b800000000 mov eax, 0
| 0x56315b93e89b e8e0fcffff call sym.imp.printf ; int printf(const char *format)
| 0x56315b93e8a0 b800000000 mov eax, 0
| 0x56315b93e8a5 488b75f8 mov rsi, qword [local_8h]
| 0x56315b93e8a9 644833342528. xor rsi, qword fs:[0x28]
| ,=< 0x56315b93e8b2 7405 je 0x56315b93e8b9
| | 0x56315b93e8b4 e8b7fcffff call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
| `-> 0x56315b93e8b9 c9 leave
\ 0x56315b93e8ba c3 ret
[0x56315b93e6aa]>
Опять же, не позволяйте этому коду вас напугать, поскольку он очень повторяется. Мы можем разделить код на две основные части: сначала код инициализирует некоторые данные, а затем распечатывает их. В этом первом разделе мы также можем определить некий шаблон, два блока, каждый из которых заканчивается одним заданием:
Код:
| 0x56315b93e72e 66c74014616c mov word [rax + 0x14], 0x6c61 ; [0x6c61:2]=0xffff
| 0x56315b93e734 c6401600 mov byte [rax + 0x16], 0
| 0x56315b93e738 c78518ffffff. mov dword [local_e8h], 0x631caf
| 0x56315b93e7b0 48894810 mov qword [rax + 0x10], rcx
| 0x56315b93e7b4 c6401800 mov byte [rax + 0x18], 0
| 0x56315b93e7b8 c745e8d41d63. mov dword [local_18h], 0x631dd4
Итак, давайте проанализируем один из них и сможем разобраться во всем. Читая сверху вниз, мы видим:
Код:
| 0x56315b93e6cb 48ba43205072. movabs rdx, 0x6172676f72502043
| 0x56315b93e6d5 488910 mov qword [rax], rdx
| 0x56315b93e6d8 c740086d6d69. mov dword [rax + 8], 0x6e696d6d ; [0x6e696d6d:4]=-1
| 0x56315b93e6df 66c7400c6700 mov word [rax + 0xc], 0x67 ; 'g' ; [0x67:2]=0xffff ; 103
| 0x56315b93e6e5 488d8550feff. lea rax, qword [local_1b0h]
Как вы можете видеть, некоторые большие шестнадцатеричные фрагменты перемещаются в память, начиная с local_1b0h, поскольку мы собираемся перемещать более крупные фрагменты. А если собрать все вместе:
432050726f6772616d6d696e67
= Программирование на C в ASCII. (помните о порядке байтов). Зная это, вы сможете разобраться в остальной части кода. Важно отметить, что хотя мы и используем strcpy, программа делает это сама, а не вызывает какую-либо функцию.
Код:
[0x56315b93e6aa]> "td struct Books { char title[50]; char author[50]; char subject[100]; int book_id;};"
[0x56315b93e6aa]> tl
[0x56315b93e6aa]> td
Invalid use of td. See td? for help
^Cx56315b93e6aa]>
[0x56315b93e6aa]>
[0x56315b93e6aa]> db 0x56315b93e6cb
[0x56315b93e6aa]> db 0x56315b93e749
[0x56315b93e6aa]> dc
hit breakpoint at: 56315b93e6cb
[0x56315b93e6aa]> afvd
var local_8h = 0x7fff0a95f358 0x4332774ba5ead400 ....Kw2C
var local_1b0h = 0x7fff0a95f1b0 0x00007fff0a95f370 p....... @rsp stack R W 0x1 --> rdi
var local_e8h = 0x7fff0a95f278 0x00007fe2f4b21710 ........ (unk0) R W 0x7fff0a9d2000 --> ([vvar]) map.vdso_._r_x R X 'jg 0x7fff0a9d2047' '[vdso]'
var local_e0h = 0x7fff0a95f280 0x00007fe2f46ba787 ..k..... (__vdso_getcpu)
var local_18h = 0x7fff0a95f348 0x000056315b93e5a0 ...[1V.. (LOAD0) (/home/red/c/chapter6/structs) r12 entry0 program R X 'xor ebp, ebp' 'structs'
[0x56315b93e6aa]> tl Books = 0x7fff0a95f1b0
[0x56315b93e6aa]> tl
(Books)
title : 0x7fff0a95f1b0 = p.....
author : 0x7fff0a95f1e2 = ....
subject : 0x7fff0a95f214 =
book_id : 0x7fff0a95f278 = 4105312016
[0x56315b93e6aa]> dc
hit breakpoint at: 56315b93e749
[0x56315b93e749]> tl
(Books)
title : 0x7fff0a95f1b0 = C Programming
author : 0x7fff0a95f1e2 = Nuha Ali
subject : 0x7fff0a95f214 = C Programming Tutorial
book_id : 0x7fff0a95f278 = 6495407
[0x56315b93e749]>
Также обратите внимание, что мы можем «связать» структуру с несколькими адресами данных и, таким образом, контролировать несколько сегментов памяти во время работы программы.
И вот и все, что касается этого поста, в следующих постах мы углубимся в эти темы.
Источник:
Ссылка скрыта от гостей
Последнее редактирование модератором: