
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.14.81] |
![]() |
|
Сообщ.
#1
,
|
|
|
Пишем простейший загрузчик PE файлов ВНИМАНИЕ статья рассчитана на читателя, который знает формат PE файлов или по крайней мере держит в руках доку. И так, чтобы не влезать в систему, и не громоздить в коде функции для работы с потоками и создания процессов, мы будем догружать PE файл в своё адресное пространство. Теперь по порядку о том, что нам нужно будет сделать: 1) Нужно будет изменить у нашего PE загрузчика базовый адрес загрузки, в FASM для этого используется специальная директива(смотри код). 2) Прочитать в память PE файл 3) Разобрать PE заголовок, определить Image Base, адрес таблицы секций 4) Разобрать таблицу секций, скопировать секции по адресам, указанным в таблице 5) Определить адрес таблицы импорта, заполнить таблицу импорта 6) Поставить заглушку на завершение программы. 7) Желательно поставить заглушку на GetModuleHandle чтобы корректно работали ресурсы. Сразу прошу прощения за плохо комментированный код ![]() ![]() ![]() format PE GUI 4.0 at 0500000h ; базовый адрес загрузки проги теперь 0500000h ; стандартно проги грузятся на 0400000h include 'win32ax.inc' ; секция данных .data h dd 0 hfile dd 0h fsize dd 0h buffer rd 512 hmem dd 0h PEa dd 0h Vsize dd 0h Vadr dd 0h Psize dd 0h Padr dd 0h Iadr dd 0h Isize dd 0h BaseAdr dd 400000h nums dd 0 hdll dd 0h fname dd 0 EDIs dd 0 ECXs dd 0 ERMSG db 'Ошибка при загрузку файла. Код ошибки <<' ERC dw 3030h db '>>. ' ;Здесь таблица с функциями, которые загрузчик перенаправит на свои заглушки HOOKTABLE: dd ExitCode1 ep db 'ExitProcess',0 dd GetMH gmh db 'GetModuleHandleA',0 .code start: ; для начала разберём параметры из командной строки invoke GetCommandLine cmp eax,0 mov [ERC],'01' je ERRORs mov edi,eax mov [EDIs],eax invoke lstrlen,edi cmp eax,0 mov [ERC],'02' je ERRORs cld inc edi mov ecx,eax mov [ECXs],eax mov al,22h repnz scasb jnz OSm2 inc edi jmp CRF OSm2: mov edi,[EDIs] mov ecx,[ECXs] mov al,20h repnz scasb mov [ERC],'03' jnz ERRORs CRF: ; теперь в fname имя файла из командной строки mov [fname],edi ; открываем файл invoke CreateFile,[fname],GENERIC_ALL,FILE_SHARE_READ,0,OPEN_EXISTING,0,0 mov [hfile],eax cmp eax,0 mov [ERC],'04' je ERRORs ; определяем размер invoke GetFileSize,[hfile],0 mov [fsize],eax cmp eax,0 mov [ERC],'05' je ERRORs ;выдиляем память invoke GlobalAlloc, GMEM_FIXED OR GMEM_ZEROINIT, eax mov [hmem],eax cmp eax,0 mov [ERC],'06' je ERRORs ; соответственно читаем файл в память :))) invoke ReadFile,[hfile],[hmem],[fsize],buffer,0 cmp eax,0 mov [ERC],'07' je ERRORs mov edx,[hmem] ; edx- указатель на начало прочитанного файла в памяти ; разбираем PE заголовок mov eax,[edx+3ch] add edx,eax ; edx- PE offset mov [PEa],edx add edx,0f8h; edx- Table offset size 2ch mov eax,[PEa] mov eax,[eax+34h] mov [BaseAdr],eax ; базовый адрес загрузки mov eax,[PEa] mov ax,[eax+06h] and eax,0ffffh mov [nums],eax ; количество обьектов (Num of Objects) mov eax,[PEa] mov eax,[eax+50h] ; виртуальный размер в байтах всего загружаемого образа add eax,100h ; выдиляем память под образ, но адресу ImageBase invoke VirtualAlloc,[BaseAdr],eax,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE cmp eax,0 mov [h],eax mov [ERC],'08' je ERRORs ; читаем в память PE ФАЙЛ invoke SetFilePointer,[hfile], 0,0, FILE_BEGIN invoke ReadFile,[hfile],[BaseAdr],[fsize],buffer,0 cmp eax,0 mov [ERC],'12' je ERRORs ; цикл по таблице секций NEXTs: dec [nums] mov edx,[PEa] add edx,0f8h push edx mov eax,[nums] mov ebx,28h mul ebx pop edx add edx,eax mov eax,[edx+08h] ;Virtual Size mov [Vsize],eax mov eax,[edx+0ch] ;Section RVA mov [Vadr],eax mov eax,[edx+10h] ;Physical Size mov [Psize],eax mov eax,[edx+14h] ;Physical Offset add eax,[hmem] mov [Padr],eax ; копируем секцию на место mov esi,[Padr] mov edi,[Vadr] add edi,[BaseAdr] mov ecx,[Psize] rep movsb cmp [nums],0 jne NEXTs ;********************************* mov eax,[PEa] mov eax,[eax+80h] ; RVA адрес таблицы импорта mov [Iadr],eax mov eax,[PEa] mov eax,[eax+84h] ; размер таблицы импорта mov [Isize],eax mov edi,[Iadr] add edi,[BaseAdr] cmp dword[edi+0ch],0 ;Ссылка на библиотеку с которой нам необходимо поиметь вызовы представлена в виде ASCIZ. cmp dword[edi+10h],0 ;Ссылка на табличку адресов импорта, заполняется системой при связывании mov [ERC],'09' je ERRORs ; цикл по таблице импорта NXTO: ; цикл по именам библиотек mov eax,[edi+0ch] add eax,[BaseAdr] ; загрузили необходимую библиотеку invoke LoadLibrary,eax cmp eax,0 mov [ERC],'10' je ERRORs mov [hdll],eax mov esi,[edi+10h] add esi,[BaseAdr] ;***************** NXTF: ; цикл по именам функций mov eax,[esi] add eax,[BaseAdr] add eax,2 ;******** ; сравним имя функции с именами для перхвата stdcall XSCAN,gmh stdcall XSCAN,ep ;******** ;опредиляем адрес функции invoke GetProcAddress,[hdll],eax cmp eax,0 mov [ERC],'11' je ERRORs mov [esi],eax OKXSCAS: add esi,4h cmp dword[esi],0 ; переход на следующее имя функции jne NXTF ;***************** add edi,14h cmp dword[edi+0ch],0 je Iok cmp dword[edi+10h],0 je Iok jmp NXTO ; переход на следующую библиотеку Iok: ;********************************* ;Таблица импорта заполнена mov edx,[PEa] add edx,28h mov eax,[edx] add eax,[BaseAdr] ; установим перехват на выход в кернел mov dword[esp+40],ExitCode2 ; переход на EP jmp eax ; Заглушки ExitCode1: invoke MessageBox,HWND_DESKTOP,'<<ExitProcess>>',"Win32 PE Loader",MB_OK invoke ExitProcess,0 ExitCode2: invoke MessageBox,HWND_DESKTOP,'Kernel return offset esp+40',"Win32 PE Loader",MB_OK invoke ExitProcess,0 GetMH: pop ebx pop eax push ebx mov eax,[BaseAdr] ret ERRORs: invoke MessageBox,HWND_DESKTOP,ERMSG,"Win32 PE Loader",MB_OK invoke ExitProcess,0 ;************************************* proc XSCAN,.XSTEMP pushad mov esi,[.XSTEMP] mov edi,eax invoke lstrlen,eax mov ecx,eax repe cmpsb popad jnz NOXSCAS ;*** mov eax,[.XSTEMP] sub eax,4 mov eax,[eax] mov [esi],eax mov dword[esp+4],OKXSCAS NOXSCAS: ret endp ;************************************* .end start Прикреплённый файл ![]() |
Сообщ.
#2
,
|
|
|
Вы гений. Это отличный код. Неточность - при открытии файла сравнивать eax нужно не с нулем, а с -1.
|