<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=148144&amp;view=findpost&amp;p=3517855</guid>
        <pubDate>Wed, 27 Aug 2014 08:12:17 +0000</pubDate>
        <title>Пишем простейший загрузчик PE файлов</title>
        <link>https://forum.sources.ru/index.php?showtopic=148144&amp;view=findpost&amp;p=3517855</link>
        <description><![CDATA[_edge [tkm]: Вы гений. Это отличный код. Неточность - при открытии файла сравнивать eax нужно не с нулем, а с -1.]]></description>
        <author>_edge [tkm]</author>
        <category>Assembler FAQ</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=148144&amp;view=findpost&amp;p=1174109</guid>
        <pubDate>Wed, 12 Jul 2006 10:17:36 +0000</pubDate>
        <title>Пишем простейший загрузчик PE файлов</title>
        <link>https://forum.sources.ru/index.php?showtopic=148144&amp;view=findpost&amp;p=1174109</link>
        <description><![CDATA[ProgramMan:  <br>
<div class='tag-align-center'><span class='tag-size' data-value='13' style='font-size:13pt;'><span class="tag-color tag-color-named" data-value="blue" style="color: blue"><strong class='tag-b'>Пишем простейший загрузчик PE файлов</strong></span></span></div><br>
<strong class='tag-b'>ВНИМАНИЕ</strong> статья рассчитана на читателя, который знает формат PE файлов или по крайней мере держит в руках доку.<br>
И так, чтобы не влезать в систему, и не громоздить в коде функции для работы с потоками и создания процессов, мы будем догружать PE файл в своё адресное пространство.<br>
Теперь по порядку о том, что нам нужно будет сделать:<br>
1)	Нужно будет  изменить у нашего PE загрузчика базовый адрес загрузки, в FASM для этого используется специальная директива(смотри код).<br>
2)	Прочитать в память PE файл<br>
3)	Разобрать PE заголовок, определить Image Base, адрес таблицы секций<br>
4)	Разобрать таблицу секций, скопировать секции по адресам, указанным в таблице<br>
5)	Определить адрес таблицы импорта, заполнить таблицу импорта<br>
6)	Поставить заглушку на завершение программы.<br>
7)	Желательно поставить заглушку на GetModuleHandle чтобы корректно работали ресурсы.<br>
<em class='tag-i'>Сразу прошу прощения за плохо комментированный код :( Программе уже не один год, и вспомнить смысл каждой строчки сложно….</em><br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">format PE GUI 4.0 at &nbsp;0500000h &nbsp; ; базовый адрес загрузки проги теперь 0500000h</div><div class="code_line">; стандартно проги грузятся на 0400000h</div><div class="code_line">include &#39;win32ax.inc&#39;</div><div class="code_line">; секция данных</div><div class="code_line">.data</div><div class="code_line">h &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dd 0</div><div class="code_line">hfile &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dd 0h</div><div class="code_line">fsize &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dd 0h</div><div class="code_line">buffer &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rd 512</div><div class="code_line">hmem &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dd 0h</div><div class="code_line">PEa &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dd 0h</div><div class="code_line">Vsize &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dd 0h</div><div class="code_line">Vadr &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dd 0h</div><div class="code_line">Psize &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dd 0h</div><div class="code_line">Padr &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dd 0h</div><div class="code_line">Iadr &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dd 0h</div><div class="code_line">Isize &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dd 0h</div><div class="code_line">BaseAdr &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dd 400000h</div><div class="code_line">nums &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dd 0</div><div class="code_line">hdll &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dd 0h</div><div class="code_line">fname &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dd 0</div><div class="code_line">EDIs &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dd 0</div><div class="code_line">ECXs &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dd 0</div><div class="code_line">ERMSG &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;db &#39;Ошибка при загрузку файла. Код ошибки &#60;&#60;&#39;</div><div class="code_line">ERC &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dw 3030h</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; db &#39;&#62;&#62;. &#39;</div><div class="code_line">;Здесь таблица с функциями, которые загрузчик перенаправит на свои заглушки</div><div class="code_line">HOOKTABLE:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dd ExitCode1</div><div class="code_line">ep &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; db &#39;ExitProcess&#39;,0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dd GetMH</div><div class="code_line">gmh &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;db &#39;GetModuleHandleA&#39;,0</div><div class="code_line">&nbsp;</div><div class="code_line">.code</div><div class="code_line">start:</div><div class="code_line">; для начала разберём параметры из командной строки</div><div class="code_line">invoke &nbsp;GetCommandLine</div><div class="code_line">cmp eax,0</div><div class="code_line">mov [ERC],&#39;01&#39;</div><div class="code_line">je ERRORs</div><div class="code_line">mov edi,eax</div><div class="code_line">mov [EDIs],eax</div><div class="code_line">invoke &nbsp;lstrlen,edi</div><div class="code_line">cmp eax,0</div><div class="code_line">mov [ERC],&#39;02&#39;</div><div class="code_line">je ERRORs</div><div class="code_line">cld</div><div class="code_line">inc edi</div><div class="code_line">mov ecx,eax</div><div class="code_line">mov [ECXs],eax</div><div class="code_line">mov al,22h</div><div class="code_line">repnz scasb</div><div class="code_line">jnz OSm2</div><div class="code_line">inc edi</div><div class="code_line">jmp CRF</div><div class="code_line">OSm2:</div><div class="code_line">mov edi,[EDIs]</div><div class="code_line">mov ecx,[ECXs]</div><div class="code_line">mov al,20h</div><div class="code_line">repnz scasb</div><div class="code_line">mov [ERC],&#39;03&#39;</div><div class="code_line">jnz ERRORs</div><div class="code_line">&nbsp;</div><div class="code_line">CRF:</div><div class="code_line">; теперь в fname имя файла из командной строки</div><div class="code_line">mov [fname],edi</div><div class="code_line">&nbsp;</div><div class="code_line">; открываем файл</div><div class="code_line">invoke &nbsp;CreateFile,[fname],GENERIC_ALL,FILE_SHARE_READ,0,OPEN_EXISTING,0,0</div><div class="code_line">mov [hfile],eax</div><div class="code_line">cmp eax,0</div><div class="code_line">mov [ERC],&#39;04&#39;</div><div class="code_line">je ERRORs</div><div class="code_line">; определяем размер</div><div class="code_line">invoke &nbsp;GetFileSize,[hfile],0</div><div class="code_line">mov [fsize],eax</div><div class="code_line">cmp eax,0</div><div class="code_line">mov [ERC],&#39;05&#39;</div><div class="code_line">je ERRORs</div><div class="code_line">;выдиляем память</div><div class="code_line">invoke &nbsp; &nbsp;GlobalAlloc, GMEM_FIXED OR GMEM_ZEROINIT, eax</div><div class="code_line">mov [hmem],eax</div><div class="code_line">cmp eax,0</div><div class="code_line">mov [ERC],&#39;06&#39;</div><div class="code_line">je ERRORs</div><div class="code_line">; соответственно читаем файл в память :)))</div><div class="code_line">invoke &nbsp;ReadFile,[hfile],[hmem],[fsize],buffer,0</div><div class="code_line">cmp eax,0</div><div class="code_line">mov [ERC],&#39;07&#39;</div><div class="code_line">je ERRORs</div><div class="code_line">&nbsp;</div><div class="code_line">mov edx,[hmem]</div><div class="code_line">; edx- указатель на начало прочитанного файла в памяти</div><div class="code_line">; разбираем PE заголовок</div><div class="code_line">mov eax,[edx+3ch]</div><div class="code_line">add edx,eax ; edx- PE offset</div><div class="code_line">mov [PEa],edx</div><div class="code_line">add edx,0f8h; edx- Table offset &nbsp; size 2ch</div><div class="code_line">&nbsp;</div><div class="code_line">mov eax,[PEa]</div><div class="code_line">mov eax,[eax+34h]</div><div class="code_line">mov [BaseAdr],eax &nbsp;; базовый адрес загрузки</div><div class="code_line">&nbsp;</div><div class="code_line">mov eax,[PEa]</div><div class="code_line">mov ax,[eax+06h]</div><div class="code_line">and eax,0ffffh</div><div class="code_line">mov [nums],eax &nbsp;; количество обьектов &nbsp;(Num of Objects)</div><div class="code_line">&nbsp;</div><div class="code_line">mov eax,[PEa]</div><div class="code_line">mov eax,[eax+50h] ; виртуальный размер в байтах всего загружаемого образа</div><div class="code_line">add eax,100h</div><div class="code_line">; выдиляем память под образ, но адресу ImageBase</div><div class="code_line">invoke VirtualAlloc,[BaseAdr],eax,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE</div><div class="code_line">cmp eax,0</div><div class="code_line">mov [h],eax</div><div class="code_line">mov [ERC],&#39;08&#39;</div><div class="code_line">je ERRORs</div><div class="code_line">; читаем в память PE ФАЙЛ</div><div class="code_line">invoke &nbsp;SetFilePointer,[hfile], 0,0, FILE_BEGIN</div><div class="code_line">invoke &nbsp;ReadFile,[hfile],[BaseAdr],[fsize],buffer,0</div><div class="code_line">cmp eax,0</div><div class="code_line">mov [ERC],&#39;12&#39;</div><div class="code_line">je ERRORs</div><div class="code_line">; цикл по таблице секций</div><div class="code_line">NEXTs:</div><div class="code_line">dec [nums]</div><div class="code_line">mov edx,[PEa]</div><div class="code_line">add edx,0f8h</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push edx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov eax,[nums]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov ebx,28h</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mul ebx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pop edx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;add edx,eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov eax,[edx+08h] ;Virtual Size</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov [Vsize],eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov eax,[edx+0ch] ;Section RVA</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov [Vadr],eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov eax,[edx+10h] ;Physical Size</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov [Psize],eax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov eax,[edx+14h] ;Physical Offset</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;add eax,[hmem]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov [Padr],eax</div><div class="code_line">; копируем секцию на место</div><div class="code_line">mov esi,[Padr]</div><div class="code_line">mov edi,[Vadr]</div><div class="code_line">add edi,[BaseAdr]</div><div class="code_line">mov ecx,[Psize]</div><div class="code_line">rep movsb</div><div class="code_line">cmp [nums],0</div><div class="code_line">jne NEXTs</div><div class="code_line">;*********************************</div><div class="code_line">mov eax,[PEa]</div><div class="code_line">mov eax,[eax+80h] ; RVA адрес таблицы импорта</div><div class="code_line">mov [Iadr],eax</div><div class="code_line">mov eax,[PEa]</div><div class="code_line">mov eax,[eax+84h] ; размер таблицы импорта</div><div class="code_line">mov [Isize],eax</div><div class="code_line">mov edi,[Iadr]</div><div class="code_line">add edi,[BaseAdr]</div><div class="code_line">cmp dword[edi+0ch],0</div><div class="code_line">;Ссылка на библиотеку с которой нам необходимо поиметь вызовы представлена в виде ASCIZ.</div><div class="code_line">cmp dword[edi+10h],0</div><div class="code_line">;Ссылка на табличку адресов импорта, заполняется системой при связывании</div><div class="code_line">mov [ERC],&#39;09&#39;</div><div class="code_line">je ERRORs</div><div class="code_line">; цикл по таблице импорта</div><div class="code_line">NXTO:</div><div class="code_line">; цикл по именам библиотек</div><div class="code_line">mov eax,[edi+0ch]</div><div class="code_line">add eax,[BaseAdr]</div><div class="code_line">; загрузили необходимую библиотеку</div><div class="code_line">invoke &nbsp;LoadLibrary,eax</div><div class="code_line">cmp eax,0</div><div class="code_line">mov [ERC],&#39;10&#39;</div><div class="code_line">je ERRORs</div><div class="code_line">mov [hdll],eax</div><div class="code_line">mov esi,[edi+10h]</div><div class="code_line">add esi,[BaseAdr]</div><div class="code_line">;*****************</div><div class="code_line">NXTF:</div><div class="code_line">; цикл по именам функций</div><div class="code_line">mov eax,[esi]</div><div class="code_line">add eax,[BaseAdr]</div><div class="code_line">add eax,2</div><div class="code_line">;********</div><div class="code_line">; сравним имя функции с именами для перхвата</div><div class="code_line">stdcall &nbsp;XSCAN,gmh</div><div class="code_line">stdcall &nbsp;XSCAN,ep</div><div class="code_line">;********</div><div class="code_line">;опредиляем адрес функции</div><div class="code_line">invoke &nbsp;GetProcAddress,[hdll],eax</div><div class="code_line">cmp eax,0</div><div class="code_line">mov [ERC],&#39;11&#39;</div><div class="code_line">je ERRORs</div><div class="code_line">&nbsp;</div><div class="code_line">mov [esi],eax</div><div class="code_line">OKXSCAS:</div><div class="code_line">add esi,4h</div><div class="code_line">cmp dword[esi],0</div><div class="code_line">; переход на следующее имя функции</div><div class="code_line">jne NXTF</div><div class="code_line">;*****************</div><div class="code_line">add edi,14h</div><div class="code_line">cmp dword[edi+0ch],0</div><div class="code_line">je Iok</div><div class="code_line">cmp dword[edi+10h],0</div><div class="code_line">je Iok</div><div class="code_line">jmp NXTO</div><div class="code_line">; переход на следующую библиотеку</div><div class="code_line">Iok:</div><div class="code_line">;*********************************</div><div class="code_line">;Таблица импорта &nbsp;заполнена</div><div class="code_line">mov edx,[PEa]</div><div class="code_line">add edx,28h</div><div class="code_line">mov eax,[edx]</div><div class="code_line">add eax,[BaseAdr]</div><div class="code_line">; установим перехват на выход в кернел</div><div class="code_line">mov dword[esp+40],ExitCode2</div><div class="code_line">; переход на EP</div><div class="code_line">jmp eax</div><div class="code_line">; Заглушки</div><div class="code_line">&nbsp;ExitCode1:</div><div class="code_line">&nbsp;&nbsp;invoke &nbsp;MessageBox,HWND_DESKTOP,&#39;&#60;&#60;ExitProcess&#62;&#62;&#39;,&quot;Win32 PE Loader&quot;,MB_OK</div><div class="code_line">&nbsp;&nbsp;invoke &nbsp;ExitProcess,0</div><div class="code_line">&nbsp;ExitCode2:</div><div class="code_line">&nbsp;&nbsp;invoke &nbsp;MessageBox,HWND_DESKTOP,&#39;Kernel return offset esp+40&#39;,&quot;Win32 PE Loader&quot;,MB_OK</div><div class="code_line">&nbsp;&nbsp;invoke &nbsp;ExitProcess,0</div><div class="code_line">&nbsp;GetMH:</div><div class="code_line">&nbsp;&nbsp;pop ebx</div><div class="code_line">&nbsp;&nbsp;pop eax</div><div class="code_line">&nbsp;&nbsp;push ebx</div><div class="code_line">&nbsp;&nbsp;mov eax,[BaseAdr]</div><div class="code_line">&nbsp;&nbsp;ret</div><div class="code_line">&nbsp;ERRORs:</div><div class="code_line">&nbsp;&nbsp;invoke &nbsp;MessageBox,HWND_DESKTOP,ERMSG,&quot;Win32 PE Loader&quot;,MB_OK</div><div class="code_line">&nbsp;&nbsp;invoke &nbsp;ExitProcess,0</div><div class="code_line">;*************************************</div><div class="code_line">proc XSCAN,.XSTEMP</div><div class="code_line">&nbsp;pushad</div><div class="code_line">&nbsp;&nbsp;mov esi,[.XSTEMP]</div><div class="code_line">&nbsp;&nbsp;mov edi,eax</div><div class="code_line">&nbsp;&nbsp;invoke &nbsp;lstrlen,eax</div><div class="code_line">&nbsp;&nbsp;mov ecx,eax</div><div class="code_line">&nbsp;&nbsp;repe cmpsb</div><div class="code_line">&nbsp;popad</div><div class="code_line">&nbsp;jnz NOXSCAS</div><div class="code_line">;***</div><div class="code_line">&nbsp;mov eax,[.XSTEMP]</div><div class="code_line">&nbsp;sub eax,4</div><div class="code_line">&nbsp;mov eax,[eax]</div><div class="code_line">&nbsp;mov [esi],eax</div><div class="code_line">&nbsp;mov dword[esp+4],OKXSCAS</div><div class="code_line">&nbsp;NOXSCAS:</div><div class="code_line">&nbsp;ret</div><div class="code_line">endp</div><div class="code_line">;*************************************</div><div class="code_line">.end start</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script>]]></description>
        <author>ProgramMan</author>
        <category>Assembler FAQ</category>
      </item>
	
      </channel>
      </rss>
	