<?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=409554&amp;view=findpost&amp;p=3684576</guid>
        <pubDate>Thu, 15 Sep 2016 14:14:26 +0000</pubDate>
        <title>Загрузчик, шеллкод, без рантайма...</title>
        <link>https://forum.sources.ru/index.php?showtopic=409554&amp;view=findpost&amp;p=3684576</link>
        <description><![CDATA[B.V.: А я и не говорил, что что-то подобное было. Под <em class='tag-i'>изучено</em> я имел ввиду изыскания Хакера с VBS]]></description>
        <author>B.V.</author>
        <category>Visual Basic: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=409554&amp;view=findpost&amp;p=3684571</guid>
        <pubDate>Thu, 15 Sep 2016 13:55:03 +0000</pubDate>
        <title>Загрузчик, шеллкод, без рантайма...</title>
        <link>https://forum.sources.ru/index.php?showtopic=409554&amp;view=findpost&amp;p=3684571</link>
        <description><![CDATA[TheTrik: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=409554&view=findpost&p=3684570'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>B.V. &#064; <time class="tag-quote__quoted-time" datetime="2016-09-15T13:50:18+00:00">15.09.16, 13:50</time></span><div class='quote '>Однако, насчет запуска без рантайма -- давно уже было изучено, что можно, но только если отказаться от классов, автоматизации, строк и прочего в коде проекта. Отсюда вытекает сомнительность пользы отлучения от рантайма.</div></div><br>
Не видел ничего подобного кроме этого проекта и драйвера.]]></description>
        <author>TheTrik</author>
        <category>Visual Basic: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=409554&amp;view=findpost&amp;p=3684570</guid>
        <pubDate>Thu, 15 Sep 2016 13:50:18 +0000</pubDate>
        <title>Загрузчик, шеллкод, без рантайма...</title>
        <link>https://forum.sources.ru/index.php?showtopic=409554&amp;view=findpost&amp;p=3684570</link>
        <description><![CDATA[B.V.: Зачетно.<br>Однако, насчет запуска без рантайма -- давно уже было изучено, что можно, но только если отказаться от классов, автоматизации, строк и прочего в коде проекта. Отсюда вытекает сомнительность пользы отлучения от рантайма.]]></description>
        <author>B.V.</author>
        <category>Visual Basic: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=409554&amp;view=findpost&amp;p=3684499</guid>
        <pubDate>Wed, 14 Sep 2016 17:50:58 +0000</pubDate>
        <title>Загрузчик, шеллкод, без рантайма...</title>
        <link>https://forum.sources.ru/index.php?showtopic=409554&amp;view=findpost&amp;p=3684499</link>
        <description><![CDATA[TheTrik: Эта функция похожа на предыдущую за исключением того что здесь используется функция <strong class='tag-b'>ShellExecuteEx</strong> вместо извлечения. Обратите внимание что каждая операция выполняется синхронно, т.е. каждый вызов процедуры <strong class='tag-b'>ShellExecuteEx</strong> ждет окончания выполнения команды.<br>
Если предыдущая функция выполнилась успешно тогда вызывается функция <strong class='tag-b'>RunProcess</strong> которая подготовливает данные для исполнения главного исполняемого файла из памяти:<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">&#39; // Run exe from project in memory</div><div class="code_line">Function RunProcess() As Boolean</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim bItem &nbsp; &nbsp; &nbsp; As BinStorageListItem: &nbsp;Dim Length &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pFileData &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get descriptor of executable file</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory bItem, ByVal pStoragesTable + ProjectDesc.storageDescriptor.dwSizeOfItem * _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ProjectDesc.storageDescriptor.iExecutableIndex, Len(bItem)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Alloc memory within top memory addresses</div><div class="code_line">&nbsp;&nbsp; &nbsp;pFileData = VirtualAlloc(ByVal 0&amp;, bItem.dwSizeOfFile, MEM_TOP_DOWN Or MEM_COMMIT, PAGE_READWRITE)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pFileData = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Copy raw exe file to this memory</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory ByVal pFileData, ByVal pFilesTable + bItem.ofstBeginOfData, bItem.dwSizeOfFile</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Free decompressed project data</div><div class="code_line">&nbsp;&nbsp; &nbsp;HeapFree GetProcessHeap(), HEAP_NO_SERIALIZE, pProjectData</div><div class="code_line">&nbsp;&nbsp; &nbsp;pProjectData = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Run exe from memory</div><div class="code_line">&nbsp;&nbsp; &nbsp;RunExeFromMemory pFileData, bItem.dwFlags And FF_IGNOREERROR</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; ----------------------------------------------------</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // An error occurs</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Clean memory</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;VirtualFree ByVal pFileData, 0, MEM_RELEASE</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // If ignore error then success</div><div class="code_line">&nbsp;&nbsp; &nbsp;If bItem.dwFlags And FF_IGNOREERROR Then RunProcess = True</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script><br>
Эта процедура выделяет память в верхних областях виртуального адресного пространства (поскольку большинство EXE файлов грузятся по довольно низким адресам (обычно 0x00400000). После этого очишается память данных проекта поскольку если EXE файл запустится, то эта память не будет освобождена, затем вызывается функция <strong class='tag-b'>RunExeFromMemory</strong> которая делает следующий шаг в загрузке EXE из памяти. Если по какой-либо причине загрузка EXE файла не состоялась то освобождается выделенная память и управление передается функции <strong class='tag-b'>Main</strong>. Итак, для того чтобы загрузить EXE файл нам нужно освободить память загрузчика, т.е. выгрузить загрузчик. Нам нужно только оставить маленькуий кусочек кода который будет загружать EXE файл и запускать его. Для этого я решил использовать шеллкод, хотя можно использовать и DLL. Шеллкод - это маленький базонезависимый код (код который не ссылается к внешним данным). Но в любом случае нам придется обеспечить доступ к API функциям из шеллкода. Мы не можем вызывать API функции непосредственно из шеллкода поскольку наш главный исполняемый файл будет выгружен и любое обращение к таблице импорта вызовет креш. Второе ограничение - это то что инструкция <strong class='tag-b'>call</strong> использует относительное смещение (это наиболее частый случай). Из этого следует что нам нужно инициализировать некие &quot;трамплины&quot; которые будут перебрасывать нас на API функции. Я решил делать это посредством <a class='tag-url' href='https://ru.wikipedia.org/wiki/%D0%9F%D0%B5%D1%80%D0%B5%D1%85%D0%B2%D0%B0%D1%82_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)' target='_blank'>сплайсинга</a>. Я просто заменяю первые 5 байт функции пусттышки на ассемблерную инструкцию <strong class='tag-b'>jmp</strong> которая ссылается на необходимую API функцию:<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">&#39; // Run EXE file by memory address</div><div class="code_line">Function RunExeFromMemory( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ByVal pExeData As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ByVal IgnoreError As Boolean) As Boolean</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim Length &nbsp;As Long: &nbsp; &nbsp;Dim pCode &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pszMsg &nbsp;As Long: &nbsp; &nbsp;Dim pMsgTable &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim index &nbsp; As Long: &nbsp; &nbsp;Dim pCurMsg &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get size of shellcode</div><div class="code_line">&nbsp;&nbsp; &nbsp;Length = GetAddr(AddressOf ENDSHELLLOADER) - GetAddr(AddressOf BEGINSHELLLOADER)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Alloc memory within top addresses</div><div class="code_line">&nbsp;&nbsp; &nbsp;pCode = VirtualAlloc(ByVal 0&amp;, Length, MEM_TOP_DOWN Or MEM_COMMIT, PAGE_EXECUTE_READWRITE)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Copy shellcode to allocated memory</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory ByVal pCode, ByVal GetAddr(AddressOf BEGINSHELLLOADER), Length</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Initialization of shellcode</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Not InitShellLoader(pCode) Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Splice CallLoader function in order to call shellcode</div><div class="code_line">&nbsp;&nbsp; &nbsp;Splice AddressOf CallLoader, pCode + GetAddr(AddressOf LoadExeFromMemory) - GetAddr(AddressOf BEGINSHELLLOADER)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Check ignore errors</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Not IgnoreError Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Alloc memory for messages table</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pMsgTable = VirtualAlloc(ByVal 0&amp;, 1024, MEM_TOP_DOWN Or MEM_COMMIT, PAGE_READWRITE)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If pMsgTable = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Skip pointers</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pCurMsg = pMsgTable + EM_END * 4</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;For index = 0 To EM_END - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Load message string</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pszMsg = GetString(MSG_LOADER_ERROR + index)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If pszMsg = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Length = SysStringLen(pszMsg)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;lstrcpyn ByVal pCurMsg, ByVal pszMsg, Length + 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Store pointer</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CopyMemory ByVal pMsgTable + index * 4, pCurMsg, Len(pCurMsg)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Next message offset</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pCurMsg = pCurMsg + (Length + 1) * 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SysFreeString pszMsg</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Call shellcode</div><div class="code_line">&nbsp;&nbsp; &nbsp;CallLoader pExeData, pCode, pMsgTable</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">CleanUp:</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pMsgTable Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;VirtualFree ByVal pMsgTable, 0, MEM_RELEASE</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pCode Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;VirtualFree ByVal pCode, 0, MEM_RELEASE</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Как видно из кода он вычисляет размер шеллкода используя разницу между крайними функциями - <strong class='tag-b'>ENDSHELLLOADER</strong> и <strong class='tag-b'>BEGINSHELLLOADER</strong>. Эти функции должны окружать наш шеллкод и иметь разный прототип поскольку VB6 компилятор может объединять идентичные функции. Затем выделяется память для самого шеллкода и он копируется в эту область памяти. После этого вызывается функция <strong class='tag-b'>InitShellLoader</strong> которая сплайсит все функции в шеллкоде:<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">&#39; // Shellcode initialization</div><div class="code_line">Function InitShellLoader( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pShellCode As Long) As Boolean</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim hLib &nbsp; &nbsp;As Long: &nbsp; &nbsp; &nbsp; &nbsp;Dim sName &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim sFunc &nbsp; As Long: &nbsp; &nbsp; &nbsp; &nbsp;Dim lpAddr &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim libIdx &nbsp;As Long: &nbsp; &nbsp; &nbsp; &nbsp;Dim fncIdx &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim libName As MessagesID: &nbsp;Dim fncName As MessagesID</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim fncSpc &nbsp;As Long: &nbsp; &nbsp; &nbsp; &nbsp;Dim splAddr As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // +----------------------------------------------------------------+</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Fixing of API addresses &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // +----------------------------------------------------------------+</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // | In order to call api function from shellcode i use splicing of |</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // | &nbsp; &nbsp;our VB functions and redirect call to corresponding api. &nbsp; &nbsp;|</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // | &nbsp; &nbsp; I did same in the code that injects to other process. &nbsp; &nbsp; &nbsp;|</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // +----------------------------------------------------------------+</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;splAddr = GetAddr(AddressOf tVirtualAlloc) - GetAddr(AddressOf BEGINSHELLLOADER) + pShellCode</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get size in bytes between stub functions</div><div class="code_line">&nbsp;&nbsp; &nbsp;fncSpc = GetAddr(AddressOf tVirtualProtect) - GetAddr(AddressOf tVirtualAlloc)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Use 3 library: kernel32, ntdll и user32</div><div class="code_line">&nbsp;&nbsp; &nbsp;For libIdx = 0 To 2</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Get number of imported functions depending on library</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Select Case libIdx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Case 0: libName = API_LIB_KERNEL32: fncIdx = 13</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Case 1: libName = API_LIB_NTDLL: &nbsp; &nbsp;fncIdx = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Case 2: libName = API_LIB_USER32: &nbsp; fncIdx = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End Select</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Get library name from resources</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;sName = GetString(libName): If sName = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Get module handle</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;hLib = GetModuleHandle(ByVal sName): If hLib = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;SysFreeString sName</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Go thru functions</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Do While fncIdx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;libName = libName + 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Get function name</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sName = GetString(libName): If sName = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Because of GetProcAddress works with ANSI string translate it to ANSI</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sFunc = ToAnsi(sName): If sFunc = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Get function address</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;lpAddr = GetProcAddress(hLib, sFunc)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SysFreeString sName: SysFreeString sFunc</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Error</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If lpAddr = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Splice stub</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Splice splAddr, lpAddr</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Next stub</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;splAddr = splAddr + fncSpc</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fncIdx = fncIdx - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Loop</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Modify CallByPointer</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpAddr = GetAddr(AddressOf CallByPointer) - GetAddr(AddressOf BEGINSHELLLOADER) + pShellCode</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // pop eax &nbsp; &nbsp;- 0x58</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // pop ecx &nbsp; &nbsp;- 0x59</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // push eax &nbsp; - 0x50</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // jmp ecx &nbsp; &nbsp;- 0xFFE1</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory ByVal lpAddr, &amp;HFF505958, 4</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory ByVal lpAddr + 4, &amp;HE1, 1</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Success</div><div class="code_line">&nbsp;&nbsp; &nbsp;InitShellLoader = True</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Splice function</div><div class="code_line">Sub Splice( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ByVal Func As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ByVal NewAddr As Long)</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Set memory permissions</div><div class="code_line">&nbsp;&nbsp; &nbsp;VirtualProtect ByVal Func, 5, PAGE_EXECUTE_READWRITE, 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory ByVal Func, &amp;HE9, 1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // JMP</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory ByVal Func + 1, NewAddr - Func - 5, 4 &nbsp; &nbsp;&#39; // Relative address</div><div class="code_line">End Sub</div></ol></div></div></div></div><br>
Вначале код вычисляет смещение первого &quot;трамплина&quot; (в нашем случае это функция <strong class='tag-b'>tVirtualAlloc</strong>) относительно начала шеллкода, и вычисляет расстояние (в байтах) между функциями &quot;трамплинами&quot;. Когда компилятор VB6 компилирует стандартный модуль он размещает функции в том же порядке в котором они определены в модуле. Необходимое условие - обеспечить уникальное возвращаемое значение для каждой функции. Затем код проходит по всем необходимым библиотекам (kernel32, ntdll, user32 - в этом порядке) и их функциям. Первая запись в ресурсах строк соответствует имени библиотеки за котором идут имена функций в этой библиотеке. Когда строка имени функции из ресурсов получена она транслируется в ANSI формат и вызывается функция <strong class='tag-b'>GetProcAddress</strong>. Затем вызывается функция <strong class='tag-b'>Splice</strong> которая собирает &quot;трамплин&quot; к необходимой функции из шеллкода. В конце модифицируется функция <strong class='tag-b'>CallByPointer</strong> для того чтобы обеспечить прыжок из шеллкода на точку входа EXE файла. Далее функция <strong class='tag-b'>RunExeFromMemory</strong> патчит функцию <strong class='tag-b'>CallLoader</strong> для того чтобы обеспечить вызов шеллкода из загрузчика. После этой операции функция формирует таблицу сообщений об ошибках (если нужно) которая представляет из себя просто набор указателей на стоки сообщений. И наконец вызывается пропатченная <strong class='tag-b'>CallLoader</strong> которая прыгает на функцию шеллкода <strong class='tag-b'>LoadExeFromMemory</strong> которая больше не расположена внутри загрузчика, а находится в верхних адресах АП процесса.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='14' style='font-size:14pt;'><strong class='tag-b'><span class="tag-color tag-color-named" data-value="orange" style="color: orange">Внутри шеллкода.</span></strong></span></div><br>
<br>
Итак, я сделал несколько функций внутри шеллкода:<ul class="tag-list"><li><strong class='tag-b'>LoadExeFromMemory</strong> - стартовая функция шеллкода; </li><li><strong class='tag-b'>GetImageNtHeaders</strong> - возвращает структуру <strong class='tag-b'>IMAGE_NT_HEADERS</strong> и ее адрес по базовому адресу; </li><li><strong class='tag-b'>GetDataDirectory</strong> - возвращает структуру <strong class='tag-b'>IMAGE_DATA_DIRECTORY</strong> и ее адрес по базовому адресу и каталоговому индексу; </li><li><strong class='tag-b'>EndProcess</strong> - показать сообщение об ошибке (если есть такое) и завершить процесс; </li><li><strong class='tag-b'>ProcessSectionsAndHeaders</strong> - выделить память под все заголовки (DOS, NT, секции) и все секции. Скопировать данные в секции; </li><li><strong class='tag-b'>ReserveMemory</strong> - зарезервировать необходимую память под EXE; </li><li><strong class='tag-b'>ProcessRelocations</strong> - настроить адреса иесли EXE был загружен не по базовому адресу; </li><li><strong class='tag-b'>ProcessImportTable</strong> - сканировать таблицу импорта EXE файла, загрузить необходимые библиотеки и заполнить таблицу адресов импорта (IAT); </li><li><strong class='tag-b'>SetMemoryPermissions</strong> - настроить разрешения памяти для каждой секции; </li><li><strong class='tag-b'>UpdateNewBaseAddress</strong> - обновить новый базовый адрес в системных структурах PEB и LDR.</li></ul>Из-за того что нельзя использовать функцию <strong class='tag-b'>VarPtr</strong>, я сделалпохожую функцию используя функцию <strong class='tag-b'>lstrcpyn</strong> - <strong class='tag-b'>IntPtr</strong>. Итак, функция <strong class='tag-b'>LoadExeFromMemory</strong> извлекает вначале заголовок NT и проверяет архитектуру процессора, является ли PE файл исполняемым и является ли он 32-битным приложением. Если проверка прошла успешно тогда шеллкод выгружает загрузчик из памяти используя функцию <strong class='tag-b'>ZwUnmapViewOfSection</strong>. Если функция выполняется успешно EXE образ загрузчика больше не находится в памяти и занимаемая им память освобождается. Отныне мы не можем напрямую вызывать API функции, теперь мы должны использовать наши &quot;трамплины&quot;:<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">&#39; // Parse exe in memory</div><div class="code_line">Function LoadExeFromMemory( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pRawData As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pMyBaseAddress As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pErrMsgTable As Long) As Boolean</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim NtHdr &nbsp; As IMAGE_NT_HEADERS</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pBase &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim index &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim iError &nbsp;As ERROR_MESSAGES</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pszMsg &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get IMAGE_NT_HEADERS</div><div class="code_line">&nbsp;&nbsp; &nbsp;If GetImageNtHeaders(pRawData, NtHdr) = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;iError = EM_UNABLE_TO_GET_NT_HEADERS</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;EndProcess pErrMsgTable, iError</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Check flags</div><div class="code_line">&nbsp;&nbsp; &nbsp;If NtHdr.FileHeader.Machine &#60;&#62; IMAGE_FILE_MACHINE_I386 Or _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; (NtHdr.FileHeader.Characteristics And IMAGE_FILE_EXECUTABLE_IMAGE) = 0 Or _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; (NtHdr.FileHeader.Characteristics And IMAGE_FILE_32BIT_MACHINE) = 0 Then Exit Function</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Release main EXE memory. After that main exe is unloaded from memory.</div><div class="code_line">&nbsp;&nbsp; &nbsp;ZwUnmapViewOfSection GetCurrentProcess(), GetModuleHandle(ByVal 0&amp;)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Reserve memory for EXE</div><div class="code_line">&nbsp;&nbsp; &nbsp;iError = ReserveMemory(pRawData, pBase)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If iError Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;EndProcess pErrMsgTable, iError</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Place data</div><div class="code_line">&nbsp;&nbsp; &nbsp;iError = ProcessSectionsAndHeaders(pRawData, pBase)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If iError Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;EndProcess pErrMsgTable, iError</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Update new base address</div><div class="code_line">&nbsp;&nbsp; &nbsp;iError = UpdateNewBaseAddress(pBase)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If iError Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;EndProcess pErrMsgTable, iError</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Import table processing</div><div class="code_line">&nbsp;&nbsp; &nbsp;iError = ProcessImportTable(pBase)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If iError Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;EndProcess pErrMsgTable, iError</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Relocations processing</div><div class="code_line">&nbsp;&nbsp; &nbsp;iError = ProcessRelocations(pBase)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If iError Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;EndProcess pErrMsgTable, iError</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Set the memory attributes</div><div class="code_line">&nbsp;&nbsp; &nbsp;iError = SetMemoryPermissions(pBase)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If iError Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;EndProcess pErrMsgTable, iError</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Release error message table</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pErrMsgTable Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;tVirtualFree pErrMsgTable, 0, MEM_RELEASE</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Call entry point</div><div class="code_line">&nbsp;&nbsp; &nbsp;CallByPointer NtHdr.OptionalHeader.AddressOfEntryPoint + pBase</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // End process</div><div class="code_line">&nbsp;&nbsp; &nbsp;EndProcess</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Затем шеллкод вызывает функцию <strong class='tag-b'>ReserveMemory</strong> показанную ниже. Эта функция извлекает заголовок NT из загружаемого EXE и пытается зарезервировать регион памяти по адресу указанному в поле <strong class='tag-b'>ImageBase</strong> размера <strong class='tag-b'>SizeOfmage</strong>. Если регион по какой-то причине не был выделен функция проверяет имеет ли EXE файл таблицу релокаций. Если так, тогда функция пытается выделять память по любому адресу. Информация о релокациях позволяет загрузить EXE по любому адресу отличному от <strong class='tag-b'>ImageBase</strong>. Она содержит все места в EXE файле где он использует абсолютную адресацию. Мы можем потом подкорректировать эти адреса используя разницу между реальным базовым адресом и адресом указанным в поле <strong class='tag-b'>ImageBase</strong>:<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">&#39; // Reserve memory for EXE</div><div class="code_line">Function ReserveMemory( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pRawExeData As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByRef pBase As Long) As ERROR_MESSAGES</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim NtHdr &nbsp; &nbsp; &nbsp; As IMAGE_NT_HEADERS</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pLocBase &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If GetImageNtHeaders(pRawExeData, NtHdr) = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ReserveMemory = EM_UNABLE_TO_GET_NT_HEADERS</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Reserve memory for EXE</div><div class="code_line">&nbsp;&nbsp; &nbsp;pLocBase = tVirtualAlloc(ByVal NtHdr.OptionalHeader.ImageBase, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;NtHdr.OptionalHeader.SizeOfImage, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;MEM_RESERVE, PAGE_EXECUTE_READWRITE)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pLocBase = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // If relocation information not found error</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If NtHdr.FileHeader.Characteristics And IMAGE_FILE_RELOCS_STRIPPED Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ReserveMemory = EM_UNABLE_TO_ALLOCATE_MEMORY</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Reserve memory in other region</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pLocBase = tVirtualAlloc(ByVal 0&amp;, NtHdr.OptionalHeader.SizeOfImage, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MEM_RESERVE, PAGE_EXECUTE_READWRITE)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If pLocBase = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ReserveMemory = EM_UNABLE_TO_ALLOCATE_MEMORY</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;pBase = pLocBase</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Если при вызове функции произошла ошибка то показывается сообщение о ней и приложение завершается. В противном случае вызывается функция <strong class='tag-b'>ProcessSectionsAndHeaders</strong>. Эта функция размещает все заголовки в выделенную память, извлекает информацию о всех секциях и копирует все данные в выделенную для них память. Если какая-либо секция имеет неинициализированные данные то этот регион заполняется нулями:<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">&#39; // Allocate memory for sections and copy them data to there</div><div class="code_line">Function ProcessSectionsAndHeaders( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pRawExeData As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pBase As Long) As ERROR_MESSAGES</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim iSec &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pNtHdr &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim NtHdr &nbsp; As IMAGE_NT_HEADERS</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim sec &nbsp; &nbsp; As IMAGE_SECTION_HEADER</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lpSec &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pData &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;pNtHdr = GetImageNtHeaders(pRawExeData, NtHdr)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pNtHdr = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ProcessSectionsAndHeaders = EM_UNABLE_TO_GET_NT_HEADERS</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Alloc memory for headers</div><div class="code_line">&nbsp;&nbsp; &nbsp;pData = tVirtualAlloc(ByVal pBase, NtHdr.OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pData = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ProcessSectionsAndHeaders = EM_UNABLE_TO_ALLOCATE_MEMORY</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Copy headers</div><div class="code_line">&nbsp;&nbsp; &nbsp;tCopyMemory pData, pRawExeData, NtHdr.OptionalHeader.SizeOfHeaders</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get address of beginnig of sections headers</div><div class="code_line">&nbsp;&nbsp; &nbsp;pData = pNtHdr + Len(NtHdr.Signature) + Len(NtHdr.FileHeader) + NtHdr.FileHeader.SizeOfOptionalHeader</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Go thru sections</div><div class="code_line">&nbsp;&nbsp; &nbsp;For iSec = 0 To NtHdr.FileHeader.NumberOfSections - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Copy section descriptor</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory IntPtr(sec.SectionName(0)), pData, Len(sec)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Alloc memory for section</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lpSec = tVirtualAlloc(sec.VirtualAddress + pBase, sec.VirtualSize, MEM_COMMIT, PAGE_READWRITE)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If lpSec = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ProcessSectionsAndHeaders = EM_UNABLE_TO_ALLOCATE_MEMORY</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; If there is initialized data</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If sec.SizeOfRawData Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Take into account &nbsp;file alignment</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If sec.SizeOfRawData &#62; sec.VirtualSize Then sec.SizeOfRawData = sec.VirtualSize</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Copy initialized data to section</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory lpSec, pRawExeData + sec.PointerToRawData, sec.SizeOfRawData</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;lpSec = lpSec + sec.SizeOfRawData</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sec.VirtualSize = sec.VirtualSize - sec.SizeOfRawData</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Fill remain part with zero</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;tFillMemory lpSec, sec.VirtualSize, 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Next section</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pData = pData + Len(sec)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Затем функция <strong class='tag-b'>LoadExeFromMemory</strong> вызывает функцию <strong class='tag-b'>UpdateNewBaseAddress</strong> которая обновляет новый базовый адрес в user-mode системных структурах. Windows создает специальную структуру называемую <strong class='tag-b'>PEB</strong> (Process Environment Block) для каждого процесса. Это очень полезная структура которая позволяет получить очень много информации о процессе. Множество API функций берут информацию из этой структуры. Для примера <strong class='tag-b'>GetModuleHandle(NULL)</strong> берет возвращаемое значение из <strong class='tag-b'>PEB.ImageBaseAddress</strong> или <strong class='tag-b'>GetModuleHandle(&quot;MyExeName&quot;)</strong> извлекает информацию из списка загруженных модулей - <strong class='tag-b'>PEB.Ldr</strong>. Нам нужно обновить эту информацию согласно новому базовому адресу для того чтобы API функции возвращали корректное значение. Вот небольшая часть структуры <strong class='tag-b'>PEB</strong>:<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">Type PEB</div><div class="code_line">&nbsp;&nbsp; &nbsp;NotUsed &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Mutant &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;ImageBaseAddress &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;LoaderData &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long &#39; // Pointer to PEB_LDR_DATA</div><div class="code_line">&nbsp;&nbsp; &nbsp;ProcessParameters &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // ....</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Нам интересно только поле <strong class='tag-b'>ImageBaseAddress</strong> и <strong class='tag-b'>LoaderData</strong>. Первое поле содержит базовый адрес EXE файла. Второе поле содержит указатель на структуру <strong class='tag-b'>PEB_LDR_DATA</strong> которая описывает все загруженные модули в процессе:<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">Type PEB_LDR_DATA</div><div class="code_line">&nbsp;&nbsp; &nbsp;Length &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Initialized &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SsHandle &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;InLoadOrderModuleList &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As LIST_ENTRY</div><div class="code_line">&nbsp;&nbsp; &nbsp;InMemoryOrderModuleList &nbsp; &nbsp; &nbsp; &nbsp; As LIST_ENTRY</div><div class="code_line">&nbsp;&nbsp; &nbsp;InInitializationOrderModuleList As LIST_ENTRY</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Эта структура содержит три двухсвязных списка что описывают каждый модуль. Список <strong class='tag-b'>InLoadOrderModuleList</strong> содержит ссылки на элементы в порядке загрузки, т.е. ссылки в этом списке расположены в порядке загрузки (первый модуль в начале). Список <strong class='tag-b'>InMemoryOrderModuleList</strong> тоже самое только в порядке расположения в памяти, а <strong class='tag-b'>InInitializationOrderModuleList</strong> в порядке инициализации. Нам нужно получить первый элемент списка <strong class='tag-b'>InLoadOrderModuleList</strong> который является указателем на структуру <strong class='tag-b'>LDR_MODULE</strong>:<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">Type LDR_MODULE</div><div class="code_line">&nbsp;&nbsp; &nbsp;InLoadOrderModuleList &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As LIST_ENTRY</div><div class="code_line">&nbsp;&nbsp; &nbsp;InMemoryOrderModuleList &nbsp; &nbsp; &nbsp; &nbsp; As LIST_ENTRY</div><div class="code_line">&nbsp;&nbsp; &nbsp;InInitOrderModuleList &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As LIST_ENTRY</div><div class="code_line">&nbsp;&nbsp; &nbsp;BaseAddress &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;EntryPoint &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfImage &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;FullDllName &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As UNICODE_STRING</div><div class="code_line">&nbsp;&nbsp; &nbsp;BaseDllName &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As UNICODE_STRING</div><div class="code_line">&nbsp;&nbsp; &nbsp;Flags &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;LoadCount &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;TlsIndex &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;HashTableEntry &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As LIST_ENTRY</div><div class="code_line">&nbsp;&nbsp; &nbsp;TimeDateStamp &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Эта структура описывает один модуль. Первый элемент списка <strong class='tag-b'>InLoadOrderModuleList</strong> является описателем главного исполняемого файла. Нам нужно изменить поле <strong class='tag-b'>BaseAddress</strong> на новый базовый адрес и сохранить изменения. Итак, для того чтобы получить адрес структуры <strong class='tag-b'>PEB</strong> мы можем использовать функцию <strong class='tag-b'>NtQueryInformationProcess</strong> которая извлекает множество полезной информации о процессе (узнать подробнее можно в книге &#39;Windows NT/2000 Native API Reference&#39; by Gary Nebbett). Структура <strong class='tag-b'>PEB</strong> может быть получена из структуры <strong class='tag-b'>PROCESS_BASIC_INFORMATION</strong> которая описывает базовую информацию о процессе:<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">Type PROCESS_BASIC_INFORMATION</div><div class="code_line">&nbsp;&nbsp; &nbsp;ExitStatus &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;PebBaseAddress &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;AffinityMask &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;BasePriority &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;UniqueProcessId &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;InheritedFromUniqueProcessId &nbsp; &nbsp;As Long</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Поле <strong class='tag-b'>PebBaseAddress</strong> содержит адрес структуры <strong class='tag-b'>PEB</strong>.<br>
Для того чтобы извлечь структуру <strong class='tag-b'>PROCESS_BASIC_INFORMATION</strong> нам нужно передать в качестве параметра класса информации значение <strong class='tag-b'>ProcessBasicInformation</strong>. Поскольку размер структуры может меняться в различных версиях Windows я использую кучу для извлечения структуры <strong class='tag-b'>PROCESS_BASIC_INFORMATION</strong>. Если размер не подходит код увеличивает размер памяти для структуры <strong class='tag-b'>PROCESS_BASIC_INFORMATION</strong> и повторяет заново пока структура не будет извлечена:<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">Function UpdateNewBaseAddress( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pBase As Long) As ERROR_MESSAGES</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pPBI &nbsp; &nbsp;As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim PBIlen &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim PBI &nbsp; &nbsp; As PROCESS_BASIC_INFORMATION: &nbsp; Dim cPEB &nbsp; &nbsp;As PEB</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ntstat &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ldrData As PEB_LDR_DATA</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ldrMod &nbsp;As LDR_MODULE</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;ntstat = tNtQueryInformationProcess(tGetCurrentProcess(), ProcessBasicInformation, IntPtr(PBI.ExitStatus), Len(PBI), PBIlen)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Do While ntstat = STATUS_INFO_LENGTH_MISMATCH</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;PBIlen = PBIlen * 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If pPBI Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tHeapFree tGetProcessHeap(), HEAP_NO_SERIALIZE, pPBI</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pPBI = tHeapAlloc(tGetProcessHeap(), HEAP_NO_SERIALIZE, PBIlen)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ntstat = tNtQueryInformationProcess(tGetCurrentProcess(), ProcessBasicInformation, pPBI, PBIlen, PBIlen)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Loop</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If ntstat &#60;&#62; STATUS_SUCCESS Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;UpdateNewBaseAddress = EM_PROCESS_INFORMATION_NOT_FOUND</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pPBI Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Copy to PROCESS_BASIC_INFORMATION</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory IntPtr(PBI.ExitStatus), pPBI, Len(PBI)</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get PEB</div><div class="code_line">&nbsp;&nbsp; &nbsp;tCopyMemory IntPtr(cPEB.NotUsed), PBI.PebBaseAddress, Len(cPEB)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Modify image base</div><div class="code_line">&nbsp;&nbsp; &nbsp;cPEB.ImageBaseAddress = pBase</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Restore PEB</div><div class="code_line">&nbsp;&nbsp; &nbsp;tCopyMemory PBI.PebBaseAddress, IntPtr(cPEB.NotUsed), Len(cPEB)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Fix base address in PEB_LDR_DATA list</div><div class="code_line">&nbsp;&nbsp; &nbsp;tCopyMemory IntPtr(ldrData.Length), cPEB.LoaderData, Len(ldrData)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get first element</div><div class="code_line">&nbsp;&nbsp; &nbsp;tCopyMemory IntPtr(ldrMod.InLoadOrderModuleList.Flink), ldrData.InLoadOrderModuleList.Flink, Len(ldrMod)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Fix base</div><div class="code_line">&nbsp;&nbsp; &nbsp;ldrMod.BaseAddress = pBase</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Restore</div><div class="code_line">&nbsp;&nbsp; &nbsp;tCopyMemory ldrData.InLoadOrderModuleList.Flink, IntPtr(ldrMod.InLoadOrderModuleList.Flink), Len(ldrMod)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">CleanUp:</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Free memory</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pPBI Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;tHeapFree tGetProcessHeap(), HEAP_NO_SERIALIZE, pPBI</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
После обновления базового адреса в системных структурах шеллкод вызывает функцию <strong class='tag-b'>ProcessImportTable</strong> которая загружает необходимые библиотеки для работы EXE файла. Вначале извлекается директория <strong class='tag-b'>IMAGE_DIRECTORY_ENTRY_IMPORT</strong> которая содержит RVA массива структур <strong class='tag-b'>IMAGE_IMPORT_DESCRIPTOR</strong>:<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">Type IMAGE_IMPORT_DESCRIPTOR</div><div class="code_line">&nbsp;&nbsp; &nbsp;Characteristics &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;TimeDateStamp &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;ForwarderChain &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;pName &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;FirstThunk &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Каждая такая структура описывает одну DLL. Поле <strong class='tag-b'>pName</strong> содержит RVA ASCIIZ строки с именем библиотеки. Поле <strong class='tag-b'>Characteristics</strong> содержит RVA таблицы импортируемых функций, а поле <strong class='tag-b'>FirstThunk</strong> содержит RVA таблицы адресов импорта (IAT). Таблица имен представляет из себя массив структур <strong class='tag-b'>IMAGE_THUNK_DATA</strong>. Эта структура представляет из себя 32 битное значение в котором если установлен старший бит остальные биты представляют из себя ординал функции (импорт по ординалу), иначе остальные биты содержат RVA имени функции предваренной значением <strong class='tag-b'>Hint</strong>. Если же структура <strong class='tag-b'>IMAGE_THUNK_DATA</strong> содержит 0 то значит список имен закончен. Если все поля структуры <strong class='tag-b'>IMAGE_IMPORT_DESCRIPTOR</strong> равны 0 это означает что список структур также окончен.<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">&#39; // Process import table</div><div class="code_line">Function ProcessImportTable( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pBase As Long) As ERROR_MESSAGES</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim NtHdr &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As IMAGE_NT_HEADERS: &nbsp; &nbsp; &nbsp; &nbsp;Dim datDirectory &nbsp; &nbsp;As IMAGE_DATA_DIRECTORY</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim dsc &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As IMAGE_IMPORT_DESCRIPTOR: Dim hLib &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim thnk &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim Addr &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim fnc &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim pData &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If GetImageNtHeaders(pBase, NtHdr) = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ProcessImportTable = EM_UNABLE_TO_GET_NT_HEADERS</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Import table processing</div><div class="code_line">&nbsp;&nbsp; &nbsp;If NtHdr.OptionalHeader.NumberOfRvaAndSizes &#62; 1 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If GetDataDirectory(pBase, IMAGE_DIRECTORY_ENTRY_IMPORT, datDirectory) = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ProcessImportTable = EM_INVALID_DATA_DIRECTORY</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // If import table exists</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If datDirectory.Size &#62; 0 And datDirectory.VirtualAddress &#62; 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Copy import descriptor</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pData = datDirectory.VirtualAddress + pBase</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory IntPtr(dsc.Characteristics), pData, Len(dsc)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Go thru all descriptors</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Do Until dsc.Characteristics = 0 And _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dsc.FirstThunk = 0 And _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dsc.ForwarderChain = 0 And _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dsc.pName = 0 And _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dsc.TimeDateStamp = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If dsc.pName &#62; 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Load needed library</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hLib = tLoadLibrary(dsc.pName + pBase)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If hLib = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ProcessImportTable = EM_LOADLIBRARY_FAILED</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If dsc.Characteristics Then fnc = dsc.Characteristics + pBase Else fnc = dsc.FirstThunk + pBase</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Go to names table</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory IntPtr(thnk), fnc, 4</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Go thru names table</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Do While thnk</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Check import type</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If thnk &#60; 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // By ordinal</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Addr = tGetProcAddress(hLib, thnk And &amp;HFFFF&amp;)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // By name</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Addr = tGetProcAddress(hLib, thnk + 2 + pBase)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Next function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fnc = fnc + 4</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory IntPtr(thnk), fnc, 4</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory dsc.FirstThunk + pBase, IntPtr(Addr), 4</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dsc.FirstThunk = dsc.FirstThunk + 4</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Loop</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Next descriptor</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pData = pData + Len(dsc)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory IntPtr(dsc.Characteristics), pData, Len(dsc)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Loop</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Функция <strong class='tag-b'>ProcessRelocation</strong> вызывается после обработки импорта. Эта функция настраивает все абсолютные ссылки (если таковые имеются). Извлекается каталог <strong class='tag-b'>IMAGE_DIRECTORY_ENTRY_BASERELOC</strong> который содержит RVA массива структур <strong class='tag-b'>IMAGE_BASE_RELOCATION</strong>. Каждый элемент этого масива содержит настройки в пределах 4Кб относительно адреса <strong class='tag-b'>VirtualAddress</strong>:<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">Type IMAGE_BASE_RELOCATION</div><div class="code_line">&nbsp;&nbsp; &nbsp;VirtualAddress &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfBlock &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Поле <strong class='tag-b'>SizeOfBlock</strong> содержит размер элемента в байтах. Массив 16-битных значений дескрипторов расположен после каждой структуры <br>
<strong class='tag-b'>IMAGE_BASE_RELOCATION</strong>. Мы можем вычислить количество этих значений по формуле: <em class='tag-i'>(SizeOfBlock - Len(IMAGE_BASE_RELOCATION)) &#092; Len(Integer)</em>. Каждый элемент массива дескрипторов имеет следующуюю структуру:<br>
<div class='tag-align-center'><img class='tag-img' src='http://thetrick.esy.es/Images/REloc_rus.png' alt='user posted image'></div><br>
Верхние 4 бита содержат тип настройки. Нам интересна только настройка <strong class='tag-b'>IMAGE_REL_BASED_HIGHLOW</strong> которая означает что нам нужно добавить разницу <em class='tag-i'>(RealBaseAddress - ImageBaseAddress)</em> к значению Long которое расположено по адресу <strong class='tag-b'>VirtualAddress</strong> + 12 младших бит дескриптора. Массив струкутр <strong class='tag-b'>IMAGE_BASE_RELOCATION</strong> заканчивается структурой где все поля заполнены нулями:<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">&#39; // Process relocations</div><div class="code_line">Function ProcessRelocations( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pBase As Long) As ERROR_MESSAGES</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim NtHdr &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As IMAGE_NT_HEADERS: &nbsp; &nbsp; &nbsp; &nbsp;Dim datDirectory &nbsp; &nbsp;As IMAGE_DATA_DIRECTORY</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim relBase &nbsp; &nbsp; &nbsp; &nbsp; As IMAGE_BASE_RELOCATION: &nbsp; Dim entriesCount &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim relType &nbsp; &nbsp; &nbsp; &nbsp; As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim dwAddress &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim dwOrig &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim pRelBase &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim delta &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim pData &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Check if module has not been loaded to image base value</div><div class="code_line">&nbsp;&nbsp; &nbsp;If GetImageNtHeaders(pBase, NtHdr) = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ProcessRelocations = EM_UNABLE_TO_GET_NT_HEADERS</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;delta = pBase - NtHdr.OptionalHeader.ImageBase</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Process relocations</div><div class="code_line">&nbsp;&nbsp; &nbsp;If delta Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Get address of relocation table</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If GetDataDirectory(pBase, IMAGE_DIRECTORY_ENTRY_BASERELOC, datDirectory) = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ProcessRelocations = EM_INVALID_DATA_DIRECTORY</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If datDirectory.Size &#62; 0 And datDirectory.VirtualAddress &#62; 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Copy relocation base</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pRelBase = datDirectory.VirtualAddress + pBase</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory IntPtr(relBase.VirtualAddress), pRelBase, Len(relBase)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Do While relBase.VirtualAddress</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // To first reloc chunk</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pData = pRelBase + Len(relBase)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;entriesCount = (relBase.SizeOfBlock - Len(relBase)) \ 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Do While entriesCount &#62; 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory IntPtr(relType), pData, 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Select Case (relType \ 4096) And &amp;HF</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Case IMAGE_REL_BASED_HIGHLOW</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Calculate address</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dwAddress = relBase.VirtualAddress + (relType And &amp;HFFF&amp;) + pBase</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Get original address</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory IntPtr(dwOrig), dwAddress, Len(dwOrig)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Add delta</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dwOrig = dwOrig + delta</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Save</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory dwAddress, IntPtr(dwOrig), Len(dwOrig)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End Select</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pData = pData + 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;entriesCount = entriesCount - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Loop</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Next relocation base</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pRelBase = pRelBase + relBase.SizeOfBlock</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory IntPtr(relBase.VirtualAddress), pRelBase, Len(relBase)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Loop</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
После настройки релокаций шеллкод вызывает функцию <strong class='tag-b'>SetMemoryPermissions</strong> которая настраивает разрешения памяти согласно полю <strong class='tag-b'>Characteristics</strong> структуры <strong class='tag-b'>IMAGE_SECTION_HEADER</strong>. Для этого просто вызывается функция <strong class='tag-b'>VirtualProtect</strong> с определенными атрибутами памяти:<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">&#39; // Set memory permissions</div><div class="code_line">Private Function SetMemoryPermissions( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pBase As Long) As ERROR_MESSAGES</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim iSec &nbsp; &nbsp;As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim pNtHdr &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim NtHdr &nbsp; As IMAGE_NT_HEADERS: &nbsp; &nbsp; &nbsp; &nbsp;Dim sec &nbsp; &nbsp; As IMAGE_SECTION_HEADER</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim Attr &nbsp; &nbsp;As MEMPROTECT: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim pSec &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ret &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;pNtHdr = GetImageNtHeaders(pBase, NtHdr)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pNtHdr = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;SetMemoryPermissions = EM_UNABLE_TO_GET_NT_HEADERS</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get address of first section header</div><div class="code_line">&nbsp;&nbsp; &nbsp;pSec = pNtHdr + 4 + Len(NtHdr.FileHeader) + NtHdr.FileHeader.SizeOfOptionalHeader</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Go thru section headers</div><div class="code_line">&nbsp;&nbsp; &nbsp;For iSec = 0 To NtHdr.FileHeader.NumberOfSections - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Copy section descriptor</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;tCopyMemory IntPtr(sec.SectionName(0)), pSec, Len(sec)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Get type</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If sec.Characteristics And IMAGE_SCN_MEM_EXECUTE Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If sec.Characteristics And IMAGE_SCN_MEM_READ Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If sec.Characteristics And IMAGE_SCN_MEM_WRITE Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Attr = PAGE_EXECUTE_READWRITE</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Attr = PAGE_EXECUTE_READ</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If sec.Characteristics And IMAGE_SCN_MEM_WRITE Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Attr = PAGE_EXECUTE_WRITECOPY</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Attr = PAGE_EXECUTE</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If sec.Characteristics And IMAGE_SCN_MEM_READ Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If sec.Characteristics And IMAGE_SCN_MEM_WRITE Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Attr = PAGE_READWRITE</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Attr = PAGE_READONLY</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If sec.Characteristics And IMAGE_SCN_MEM_WRITE Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Attr = PAGE_WRITECOPY</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Attr = PAGE_NOACCESS</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Set memory permissions</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If tVirtualProtect(sec.VirtualAddress + pBase, sec.VirtualSize, Attr, IntPtr(ret)) = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SetMemoryPermissions = EM_UNABLE_TO_PROTECT_MEMORY</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Next section</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pSec = pSec + Len(sec)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
В конце концов очищается таблица сообщений об ошибках (если нужно) и вызывается точка входа загруженного EXE. В предыдущей версии загрузчика я выгружал шеллкод тоже, но некоторые EXE не вызывают <strong class='tag-b'>ExitProcess</strong> следовательно это могло вызывать креши. Загрузчик готов.<br>
Хотя мы написал загрузчик без использвания рантайма, компилятор VB6 добавляет его все-равно поскольку все OBJ файлы имеют ссылки на MSVBVM60 во время компиляции. Нам придется удалить рантайм из таблицы импорта загрузчика вручную. Для этого я сделал специальную утилиту - <strong class='tag-b'>Patcher</strong> которая ищет рантайм в таблице импорта и таблице связанного импорта и удаляет его оттуда. Эта утилита также была полезна для <a class='tag-url' href='http://bbs.vbstreets.ru/viewtopic.php?f=99&t=46839' target='_blank'>драйвера режима ядра</a>. Я не буду описывать ее работу поскольку она использует те же концепции PE-формата что я уже описал здесь. В общем и целом мы сделали рабочий EXE который не использует MSVBVM60 на целевой машине.<br>
Для того чтобы использовать загрузчик нужно скомпилировать его затем с помощью патчера пропатчить его. После этог можно использовать его в компиляторе.<br>
 <br>
Я надеюсь вам понравилось. Спасибо за внимание&#33;<br>
С уважением,<br>
Кривоус Анатолий (The trick).<br>
<span class="b-attach" data-size="180672" data-hits="207" data-attach-id="50147" data-attach-post-id="0">
			<span class="b-attach__title"></span><a class='b-attach-link' href='https://forum.sources.ru/index.php?act=Attach&amp;type=post&amp;id=0&amp;attach_id=50147' title='Скачать файл' target='_blank'>VBLoader.zip</a> (, : 207)
		</span>]]></description>
        <author>TheTrik</author>
        <category>Visual Basic: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=409554&amp;view=findpost&amp;p=3684497</guid>
        <pubDate>Wed, 14 Sep 2016 17:48:00 +0000</pubDate>
        <title>Загрузчик, шеллкод, без рантайма...</title>
        <link>https://forum.sources.ru/index.php?showtopic=409554&amp;view=findpost&amp;p=3684497</link>
        <description><![CDATA[TheTrik: <div class='tag-align-center'><a class='tag-url' href='https://www.youtube.com/watch?v=ANe_8nckVbc' target='_blank'>https://www.youtube.com/watch?v=ANe_8nckVbc</a></div><br>
Всем привет&#33; Когда-то давно я исследовал PE-формат, в особенности EXE. Я решил создать простой загрузчик исполняемых файлов специально для VB6-скомпилированных приложений. Этот загрузчик, по моим задумкам, должен загружать любое VB6-скомпилированное приложение из памяти, миную запись в файл. ВСЕ ЭТО БЫЛО СДЕЛАНО ДЛЯ ЭКСПЕРИМЕНТАЛЬНЫХ ЦЕЛЕЙ ДЛЯ ТОГО ЧТОБЫ ПРОВЕРИТЬ ТАКУЮ ВОЗМОЖНОСТЬ НА VB6. Из-за того что VB6-скомпилированные приложения не используют большинство PE-фичей это было довольно легкой задачей. Также большинство программистов говорят что любая VB6-скомпилированная программа неукоснительно связана с VB6-рантаймом (msvbvm60) и что такая программа не будет работать без рантайма и рантайм является довольно медленным. Сегодня я докажу что можно написать приложение абсолютно не использующее  рантайм (хотя я такое уже делал в драйвере). Я думаю что это могло бы быть интересным для тех кто хочет изучить базовые принципы работы с PE файлами.<br>
Прежде чем мы начнем я бы хотел сказать пару слов о проектах. Эти проекты не тестировались достаточно хорошо, поэтому они могут содержать различные проблемы. Также загрузчик не поддерживает множество возможностей PE-файлов следовательно некоторые приложения могут не работать.<br>
Итак...<br>
Этот обзор включает три проекта:<ul class="tag-list"><li>Compiler - самый большой проект из всех. Он позволяет создавать лаунчер базируемый на загрузчике, пользовательских файлах, командах и манифесте;</li><li>Loader - простейший загрузчик который выполняет команды, распаковывает файлы и запускает EXE из памяти;</li><li>Patcher - маленькая утилита которая удаляет рантайм из VB6-скомпилированного приложения.</li></ul>Я буду называть EXE что содержит команды, файлы и исполнительный файл - инсталляцией. Главная идея этой задумки - это положить информацию об инсталляции в ресурсы загрузчика. Когда загрузчик загружается он считывает эту информацию и выполняет команды из ресурсов. Я решил использовать специальное хранилище для хранения файлов и EXE и отдельное хранилище для команд.<br>
Перое хранилище хранит все файлы которые будут распакованы и главный EXE который будет запускаться из памяти. Второе хранилище хранит команды которые будут переданы в функцию <strong class='tag-b'>ShellExecuteEx</strong> после процесса того как процесс распаковки будет окончен. <br>
Загрузчик поддерживает следующие подставляемые символы (для путей):<ul class="tag-list"><li>&lt;app&gt; - путь, откуда запущен EXE;</li><li>&lt;win&gt; - системная директория;</li><li>&lt;sys&gt; - System32;</li><li>&lt;drv&gt; - системный диск;</li><li>&lt;tmp&gt; - временная директория;</li><li>&lt;dtp&gt; - рабочий стол.</li></ul><br>
<div class='tag-align-center'><span class='tag-size' data-value='14' style='font-size:14pt;'><strong class='tag-b'><span class="tag-color tag-color-named" data-value="orange" style="color: orange">Компилятор.</span></strong></span><br>
<br>
<img class='tag-img' src='http://thetrick.esy.es/Images/Compiler.png' alt='user posted image'></div><br>
<br>
Это приложение формирующее информацию для инсталляции и размещающее ее в ресурсах загрузчика. Вся информация хранится в файлах проекта. Вы можете сохранять и загружать проекты из файлов. Класс <strong class='tag-b'>clsProject</strong> описывает такой проект. Компилятор содержит 3 секции: storage, execute, mainfest.<br>
Секция &#39;storage&#39; позволяет добавлять файлы которые будут скопированы в момент запуска приложения. Каждая запись в списке имеет флаги: &#39;replace if exists&#39;, &#39;main executable&#39;, &#39;ignore error&#39;. Если выбрана &#39;replace if exists&#39; то файл будет скопирован из ресурсов даже если он есть на диске. Флаг &#39;main executable&#39; может быть установлен только единственного исполняемого файла который будет запущен когда все операции будут исполнены. И наконец &#39;ignore error&#39; просто заставляет игнорировать все ошибки и не выводить сообщения. Порядок расположения записей в списке соответствует порядку распаковки файлов, исключая главный исполняемый файл. Главный исполняемый файл не извлекается и запускается после всех операций. Класс <strong class='tag-b'>clsStorage</strong> описывает данную секцию. Этот класс содержит коллекцию объектов класса <br>
<strong class='tag-b'>clsStorageItem</strong> и дополнительные методы. Свойство <strong class='tag-b'>MainExecutable</strong> определяет индекс главного исполняемого файла в хранилище. Когда этот параметр равен -1 значит главный исполняемый файл не задан. Класс <strong class='tag-b'>clsStoragaItem</strong> описывает одну запись из списка хранилища, который содержит свойства определяющие поведение итема. Секция &#39;storage&#39; полезна если вы хотите скопировать файлы на диск перед выполнением главного приложения (различные ресурсы/OCX/DLL и т.п.).<br>
Следующая секция называется &#39;execute&#39;. Она содержит список выполняемых команд. Эти команды просто передаются в функцию <strong class='tag-b'>ShellExecuteEx</strong>. Таким образом можно к примеру зарегистрировать библиотеки или сделать что-то еще. Каждый элемент этого списка имеет два свойства: путь и параметры. Стоит отметить что все команды выполняються синхронно в порядке заданным в списке. Также каждый элемент списка может иметь флаг &#39;ignore error&#39; который предотвращает вывод каких-либо сообщений об ошибках. Секция &#39;execute&#39; представлена двумя классами <strong class='tag-b'>clsExecute</strong> and <strong class='tag-b'>clsExecuteItem</strong> которые очень похожи на классы хранилища.<br>
Последняя секция - &#39;manifest&#39;. Это просто текстовый файл который добавляеться в финальный файл в качестве манифеста. Для того чтобы включить манифест в EXE нужно просто выбрать флажок &#39;include manifest&#39; во вкладке &#39;mainfest&#39;. Это может быть полезно для использования библиотек без регистрации, визуальных стилей и т.п.<br>
Все классы ссылаються на объект проекта (<strong class='tag-b'>clsProject</strong>) который управляет ими. Каждый класс который ссылается на проект может быть сохранен или заружен используя <strong class='tag-b'>PropertyBag</strong> в качестве контейнера. Все ссылки сохраняються с относительными путями (как в .vbp файле) поэтому можно перемещать папку с проектом без проблем с путями. Для того чтобы транслировать из/то относительного/абсолютного пути я использовал функции <strong class='tag-b'>PathRelativePathTo</strong> и <strong class='tag-b'>PathCanonicalize</strong>.<br>
Итак, это была базовая информация о проекте Compiler. Сейчас я расскажу о процедуре компиляции. Как я уже сказал вся информация об инсталляции сохраняется в ресурсы загрузчика. Вначале на нужно определить формат данных:<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">&#39; // Storage list item</div><div class="code_line">Private Type BinStorageListItem</div><div class="code_line">&nbsp;&nbsp; &nbsp;ofstFileName &nbsp; &nbsp; &nbsp; &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Offset of file name</div><div class="code_line">&nbsp;&nbsp; &nbsp;ofstDestPath &nbsp; &nbsp; &nbsp; &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Offset of file path</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwSizeOfFile &nbsp; &nbsp; &nbsp; &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Size of file</div><div class="code_line">&nbsp;&nbsp; &nbsp;ofstBeginOfData &nbsp; &nbsp; As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Offset of beginning data</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwFlags &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As FileFlags &nbsp; &nbsp; &nbsp; &#39; // Flags</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Execute list item</div><div class="code_line">Private Type BinExecListItem</div><div class="code_line">&nbsp;&nbsp; &nbsp;ofstFileName &nbsp; &nbsp; &nbsp; &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Offset of file name</div><div class="code_line">&nbsp;&nbsp; &nbsp;ofstParameters &nbsp; &nbsp; &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Offset of parameters</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwFlags &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As ExeFlags &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Flags</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Storage descriptor</div><div class="code_line">Private Type BinStorageList</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwSizeOfStructure &nbsp; As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Size of structure</div><div class="code_line">&nbsp;&nbsp; &nbsp;iExecutableIndex &nbsp; &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Index of main executable</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwSizeOfItem &nbsp; &nbsp; &nbsp; &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Size of BinaryStorageItem structure</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwNumberOfItems &nbsp; &nbsp; As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Number of files in storage</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Execute list descriptor</div><div class="code_line">Private Type BinExecList</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwSizeOfStructure &nbsp; As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Size of structure</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwSizeOfItem &nbsp; &nbsp; &nbsp; &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Size of BinaryExecuteItem structure</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwNumberOfItems &nbsp; &nbsp; As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Number of items</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Base information about project</div><div class="code_line">Private Type BinProject</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwSizeOfStructure &nbsp; As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Size of structure</div><div class="code_line">&nbsp;&nbsp; &nbsp;storageDescriptor &nbsp; As BinStorageList &nbsp;&#39; // Storage descriptor</div><div class="code_line">&nbsp;&nbsp; &nbsp;execListDescriptor &nbsp;As BinExecList &nbsp; &nbsp; &#39; // Command descriptor</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwStringsTableLen &nbsp; As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Size of strings table</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwFileTableLen &nbsp; &nbsp; &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Size of data table</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Структура <strong class='tag-b'>BinProject</strong> размещается в начале ресурсов. Заметьте что проект сохраняется как <strong class='tag-b'>RT_RCDATA</strong> с именем <strong class='tag-b'>PROJECT</strong>. Поле <strong class='tag-b'>dwSizeOfStructure</strong> определяет размер структуры <strong class='tag-b'>BinProject</strong>. <strong class='tag-b'>storageDescriptor</strong> и <strong class='tag-b'>execListDescriptor</strong> определяют описатели хранилища и команд соответственно. Поле <strong class='tag-b'>dwStringsTableLen</strong> показывает размер строковой таблицы. Строковая таблица содержит все имена и команды в формате UNICODE. Поле <strong class='tag-b'>dwFileTableLen</strong> определяет размер всех данных в хранилище. И хранилище <strong class='tag-b'>BinStorageList</strong> и списки команд <strong class='tag-b'>BinExecList</strong> также имеют поля <strong class='tag-b'>dwSizeOfItem</strong> и <strong class='tag-b'>dwSizeOfStructure</strong> которые определяют размер структуры описателя и размер одного элемента в списке. Эти структуры также содержат поле <strong class='tag-b'>dwNumberOfItems</strong> которое показывает количество элементов в списке. Поле <strong class='tag-b'>iExecutableIndex</strong> содержит индекс исполняемого файла в хранилище. Общая структура показана на рисунке:<br>
<br>
<div class='tag-align-center'><img class='tag-img' src='http://thetrick.esy.es/Images/BinProject_rus.png' alt='user posted image'></div><br>
<br>
Любой элемент может ссылаться на таблицу строк и таблицу файлов. Для этой цели используется смещение относительно начала таблицы. Все итемы расположены одна за другой. Теперь мы знаем внутренний формат проекта и можем поговорить о том как постороить загрузчик который будет содержать эти данные. Как я уже сказал мы сохраняем данные в ресурсы загрузчика. О самом загрузчике я расскажу позднее, а сейчас я хотел бы заметить одну важную особенность. Когда мы ложим данные проекта в EXE файл загрузчика то это не затрагивает другие данные в ресурсах. Для примера, если запустить такой EXE то информация хранящаяся в ресурсах внутреннего EXE не будет загружена. Тоже самое относится к иконкам и версии приложения. Для избежания данных проблем нужно скопировать все ресурсы из внутреннего EXE в загрузчик. WinAPI предоставляет набор функций для замены ресурсов. Для того чтобы получить список ресурсов нам нужно распарсить EXE файл и извлечь данные. Я написал функцию <strong class='tag-b'>LoadResources</strong> которая извлекает все ресурсы EXE файла в массив.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='14' style='font-size:14pt;'><strong class='tag-b'><span class="tag-color tag-color-named" data-value="orange" style="color: orange">PE формат.</span></strong></span></div><br>
<br>
Для того чтобы получить ресурсы из EXE файла, запустить EXE из памяти и хорошо разбираться в структуре EXE фала мы должны изучить PE (portable executable) формат. PE формат имеет довольно сложную структуру. Когда загрузчик запускает PE file (exe или dll) он делает довольно много работы. Каждый PE файл начинается со специальной структуры <strong class='tag-b'>IMAGE_DOS_HEADER</strong> aka. DOS-заглушка. Поскольку и DOS и Windows приложения имеют расширение exe существует возможность запуска exe файла в DOS, но если попытаться сделать это в DOS то он выполнит это заглушку. Обычно в этом случае показываетсясообщение: &quot;This program cannot be run in DOS mode&quot;, но мы можем написать там любую программу:<br>
<br>
<div class='tag-align-center'><img class='tag-img' src='http://thetrick.esy.es/Images/DOs.png' alt='user posted image'></div><br>
<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">Type IMAGE_DOS_HEADER</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_magic &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_cblp &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_cp &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_crlc &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_cparhdr &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_minalloc &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_maxalloc &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_ss &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_sp &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_csum &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_ip &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_cs &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_lfarlc &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_ovno &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_res(0 To 3) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_oemid &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_oeminfo &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_res2(0 To 9) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;e_lfanew &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Но поскольку мы не пишем DOS программы для нас эта структура не важна. Нам интересно только поля <strong class='tag-b'>e_magic</strong> и <strong class='tag-b'>e_lfanew</strong>. Первое поле должно содержать сигнатуру &#39;MZ&#39; aka. <strong class='tag-b'>IMAGE_DOS_SIGNATURE</strong> а второе смещение до очень важной структуры <strong class='tag-b'>IMAGE_NT_HEADERS</strong>:<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">Type IMAGE_NT_HEADERS</div><div class="code_line">&nbsp;&nbsp; &nbsp;Signature &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;FileHeader &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As IMAGE_FILE_HEADER</div><div class="code_line">&nbsp;&nbsp; &nbsp;OptionalHeader &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As IMAGE_OPTIONAL_HEADER</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Первое поле этой структуры содержит сигнатуру &#39;PE&#092;0&#092;0&#39; (aka. <strong class='tag-b'>IMAGE_NT_SIGNATURE</strong>). Следующее поле описывает исполняемый файл и имеет следующий формат:<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">Type IMAGE_FILE_HEADER</div><div class="code_line">&nbsp;&nbsp; &nbsp;Machine &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;NumberOfSections &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;TimeDateStamp &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;PointerToSymbolTable &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;NumberOfSymbols &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfOptionalHeader &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;Characteristics &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Поле <strong class='tag-b'>Machine</strong> определяет архитектуру процессора и должно иметь значение <strong class='tag-b'>IMAGE_FILE_MACHINE_I386</strong> в нашем случае. Поле <strong class='tag-b'>NumberOfSections</strong> определяет количество секций в PE файле.<br>
<ul class="tag-list"><li><span class='tag-size' data-value='8' style='font-size:8pt;'>Любой EXE файл содержит секции. Каждая секция занимает место в адресном пространстве процесса и опционально в файле. Секция может содержать как код так и данные (инизиализированные или не), а также имеет имя. Наиболее распространенные имена: <strong class='tag-b'>.text</strong>, <strong class='tag-b'>.data</strong>, <strong class='tag-b'>.rsrc</strong>. Обычно секция <strong class='tag-b'>.text</strong> содержит код, <strong class='tag-b'>.data</strong> инициализированные данные, а <strong class='tag-b'>.rsrc</strong> - ресурсы. Можно изменять это поведение используя дериктивы линкера. Каждая секция имеет адрес называемый виртуальным адресом. В общем в PE формате существует несколько типов адресации. Первый - относительный виртуальный адрес (RVA). Из-за того что PE фал может быть загружен по любому адресу все ссылки внутри PE файла имеют относительную адресацию. RVA - это смещение относительно базового адреса (адреса первого байта PE-образа в памяти). Сумма RVA и базового адреса называется виртуальным адресом (VA). Также существует RAW-смещение которое показывает смещение относительно начала файла относительно RVA. Заметьте что RVA &lt;&gt; RAW. Когда модуль загружается каждая секция размещается по виртуальному адресу. Для примера модуль может иметь секцию что не имеет инициализированных данных. Такая секция не будет занимать место в PE-файле, но будет в памяти. Это очень важный момент поскольку мы будем работать с сырым EXE файлом.</span></li></ul>Поле <strong class='tag-b'>TimeDateStamp</strong> содержит дату создания PE модуля в формате UTC. Поля <strong class='tag-b'>PointerToSymbolTable</strong> and <strong class='tag-b'>NumberOfSymbols</strong> содержат информацию о символах в PE файлах. В общем эти поля содержат нули, но эти поля всегда используються в объектных файлах (*.OBJ, *.LIB) для разрешения ссылок во время линковки а также содержат отладочную информацию для PE модуля. Следующее поле <strong class='tag-b'>SizeOfOptionalHeader</strong> содержит размер структуры расположенной после <strong class='tag-b'>IMAGE_FILE_HEADER</strong> так называемой <strong class='tag-b'>IMAGE_OPTIONAL_HEADER</strong> которая всегда присутствует в PE файлах (хотя может отсутствовать в OBJ файлах). Эта структура являеться очень важной для загрузки PE модуля в память. Заметьте что эта структура различается в 32 битных и 64 битных PE-модулях. И наконец поле <strong class='tag-b'>Characteristics</strong> содержит PE-аттрибуты.<br>
Структура <strong class='tag-b'>IMAGE_OPTIONAL_HEADER</strong> имеет следующий формат:<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">Type IMAGE_OPTIONAL_HEADER</div><div class="code_line">&nbsp;&nbsp; &nbsp;Magic &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;MajorLinkerVersion &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;MinorLinkerVersion &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfCode &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfInitializedData &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfUnitializedData &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;AddressOfEntryPoint &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;BaseOfCode &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;BaseOfData &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;ImageBase &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SectionAlignment &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;FileAlignment &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;MajorOperatingSystemVersion &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;MinorOperatingSystemVersion &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;MajorImageVersion &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;MinorImageVersion &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;MajorSubsystemVersion &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;MinorSubsystemVersion &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;W32VersionValue &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfImage &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfHeaders &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;CheckSum &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SubSystem &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;DllCharacteristics &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfStackReserve &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfStackCommit &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfHeapReserve &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfHeapCommit &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;LoaderFlags &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;NumberOfRvaAndSizes &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;DataDirectory(15) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As IMAGE_DATA_DIRECTORY</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Первое поле содержит тип образа (x86, x64 или ROM образ). Нас интересует только <strong class='tag-b'>IMAGE_NT_OPTIONAL_HDR32_MAGIC</strong> который представляет собой 32 битное приложение. Следующие 2 поля не являются важными (они использовались на старых системах) и содержат 4. Следующая группа полей содержит размер всех секций с кодом, инициализированными данными и неинициализированными данными. Эти значения должны быть кратными значению <strong class='tag-b'>SectionAlignment</strong> этой структуры (см. далее). Поле <strong class='tag-b'>AddressOfEntryPoint</strong> является очень важным RVA значением которое определяет точку входа в программу. Мы будем использовать это поле когда загрузим PE образ в память для запуска кода. Следующим важным полем является <strong class='tag-b'>ImageBase</strong> которое задает предпочитаемый виртуальный адрес загрузки модуля. Когда загрузчик начинает загружать модуль, то он старается сделать это по предпочитаемому виртуальному адресу (находящимся в <strong class='tag-b'>ImageBase</strong>). Если этот адрес занят, то загрузчик проверяет поле <strong class='tag-b'>Characteristics</strong> структуры <strong class='tag-b'>IMAGE_FILE_HEADER</strong>. Если это поле содержит флаг <strong class='tag-b'>IMAGE_FILE_RELOCS_STRIPPED</strong> то модуль не сможет быть загружен. Для того чтобы загрузить такие модули нам нужно добавить информацию о релокации которая позволит загрузчику настроить адреса внутри PE-образа если модуль не может загрузится по предпочитаемому базовому адресу. Мы будем использоват это поле вместе с <strong class='tag-b'>SizeOfImage</strong> для того чтобы зарезервировать память под распакованный EXE. Поля <strong class='tag-b'>SectionAlignment</strong> and <strong class='tag-b'>FileAlignment</strong> содержат выравнивание секций в памяти и в файле соответственно. Изменяя файловое выравнивание можно уменьшить размер PE файла, но система может не загрузить данный PE файл. Выравнивание секций обычно равно размеру страницы в памяти. Поле <strong class='tag-b'>SizeOfHeaders</strong> задает размер всех заголовков (DOS Заголовок, NT заголовок, заголовки секций) выровненное на <strong class='tag-b'>FileAlignment</strong>. Значения <strong class='tag-b'>SizeOfStackReserve</strong> и <strong class='tag-b'>SizeOfStackCommit</strong> определяют общий размер стека и начальный размер стека. Тоже самое и для полей <strong class='tag-b'>SizeOfHeapReserve</strong> и <strong class='tag-b'>SizeOfHeapCommit</strong>, но для кучи. Поле <strong class='tag-b'>NumberOfRvaAndSizes</strong> содержит количество элементов в массиве <strong class='tag-b'>DataDirectory</strong>. Это поле всегда равно 16. Массив <strong class='tag-b'>DataDirectory</strong> является также очень важным поскольку в нем содержатся каталоги данных которые содержат нужную информацию об импорте, экспорте, ресурсах, релокациях и т.д. Мы будем использовать только несколько элементов из этого каталога которые используются VB6 компилятором. Я расскажу о каталогах немного позже, давайте посмотрим что находится за каталогами. За каталогами содержаться описатели секций. Количество этих описателей, если вспомнить, мы получили из структуры <strong class='tag-b'>IMAGE_FILE_HEADER</strong>. Рассмотрим формат заголовка секции:<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">Type IMAGE_SECTION_HEADER</div><div class="code_line">&nbsp;&nbsp; &nbsp;SectionName(7) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;VirtualSize &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;VirtualAddress &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;SizeOfRawData &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;PointerToRawData &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;PointerToRelocations &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;PointerToLinenumbers &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;NumberOfRelocations &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;NumberOfLinenumbers &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;Characteristics &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Первое поле содержит имя секции в формате UTF-8 c завершающим нуль-терминалом. Это имя ограничено 8-ю символами (если имя секции имеет размер 8 символов то нуль-терминатор игнорируется). COFF файл может иметь имя больше чем 8 символов в этом случае имя начинается с символа &#39;/&#39; за которым следует ASCII строка с десятичным значением смещения в строковой таблице (поле <strong class='tag-b'>IMAGE_FILE_HEADER</strong>). PE файл не поддерживает длинные имена секций. Поля <strong class='tag-b'>VirtualSize</strong> и <strong class='tag-b'>VirtualAddress</strong> содержат размер секции в памяти и адрес (RVA). Поля <strong class='tag-b'>SizeOfRawData</strong> и <strong class='tag-b'>PointerToRawData</strong> содержат RAW адрес данных в файле (если секция содержит инициализированные данные). Это ключевой момент потому что мы можем вычислить RAW адрес с помощью относительного виртуального адреса используя информацию из заголовка секций. Я написал функцию для перевода RVA адресации в RAW смещение в файле:<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">&#39; // RVA to RAW</div><div class="code_line">Function RVA2RAW( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal rva As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByRef sec() As IMAGE_SECTION_HEADER) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim index As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;For index = 0 To UBound(sec)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If rva &#62;= sec(index).VirtualAddress And _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rva &#60; sec(index).VirtualAddress + sec(index).VirtualSize Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RVA2RAW = sec(index).PointerToRawData + (rva - sec(index).VirtualAddress)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;RVA2RAW = rva</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Эта функция перечисляет все секции и проверяет если переданный адрес находится в пределах секции. Следующие 5 полей используються только в COFF файлах и не важны в PE файлах. Поле <strong class='tag-b'>Characteristics</strong> содержит атрибуты секции такие как права доступа к памяти и управление. Мы будем использовать это поле для защиты памяти exe файла в загрузчике. <br>
Давайте теперь вернемся к каталогам данных. Как мы видели существует 16 элементов в данном каталоге. Обычно PE файл не использует их все. Давайте рассмотрим структуру элемента каталога:<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">Private Type IMAGE_DATA_DIRECTORY</div><div class="code_line">&nbsp;&nbsp; &nbsp;VirtualAddress &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Size &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Эта структура содержит два поля. Первое поле содержит RVA адрес данных каталога, воторое - размер. Когда элемент каталога не представлен в PE файле то оба поля содержат нули. Вообще большинство VB6-компилируемых приложений имеют  только 4 каталога: таблица импорта, таблица ресурсов, таблица связанного импорта и таблица адресов импорта (IAT). Сейчас мы рассмотрим таблицу ресурсов которая имеет индекс <strong class='tag-b'>IMAGE_DIRECTORY_ENTRY_RESOURCE</strong> потому что мы работаем с этой информацией в проекте Compiler.<br>
Все ресурсы в EXE файле представлены в виде трехуровнего дерева. Первый уровень определяет тип ресурса (RT_BITMAP, RT_MANIFEST, RT_RCDATA, и т.д.), следующий - идентификатор ресурса и наконец третий - язык. В стандартном редакторе ресурсов VB Resource Editor можно изменять только первые 2 уровня. Все ресурсы размещаются таблице ресурсов расположенной в секции <strong class='tag-b'>.rsrc</strong> EXE файла. Благодаря такой структуре мы можем изменять ресурсы даже в готовом EXE файле. Для того чтобы добраться до самих данных в секции ресурсов нам сначала нужно прочитать <strong class='tag-b'>IMAGE_DIRECTORY_ENTRY_RESOURCE</strong> из опционального хидера. Поле <strong class='tag-b'>VirtualAddress</strong> содержит RVA таблицы ресурсов которая имеет следующий формат:<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">Type IMAGE_RESOURCE_DIRECTORY</div><div class="code_line">&nbsp;&nbsp; &nbsp;Characteristics &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;TimeDateStamp &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;MajorVersion &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;MinorVersion &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;NumberOfNamedEntries &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;NumberOfIdEntries &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Эта структура описывает все ресурсы в PE файле. Первые 4 поля не важны для нас; поле <strong class='tag-b'>NumberOfNamedEntries</strong> и <strong class='tag-b'>NumberOfIdEntries</strong> содержат количество именованных записей и записей с числовыми идентификаторами соответственно. Для примера, когда мы добавляем картинку в стандартном редакторе это добавит запись с числовым идентификатором равным 2 (<strong class='tag-b'>RT_BITMAP</strong>). Сами записи расположены сразу после <strong class='tag-b'>IMAGE_RESOURCE_DIRECTORY</strong> и имеют следующую структуру:<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">Type IMAGE_RESOURCE_DIRECTORY_ENTRY</div><div class="code_line">&nbsp;&nbsp; &nbsp;NameId &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;OffsetToData &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Первое поле этой структуры определяет является ли это именованной запись либо это запись с числовым идентификатором в зависимости от старшего бита. Если этот бит установлен то остальные биты определяют смещение от начала ресурсов к структуре <strong class='tag-b'>IMAGE_RESOURCE_DIR_STRING_U</strong> которая имет следующий формат:<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">Type IMAGE_RESOURCE_DIR_STRING_U</div><div class="code_line">&nbsp;&nbsp; &nbsp;Length &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;NameString &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As String</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Заметьте что это не правильная VB-структура и показана для наглядности. Первые два байта являются беззнаковым целым которые показывают длину строки в формате UNICODE (в символах) которая следует за ними. Таким образом для того чтобы получить строку нам нужно прочитать первые два байта с размером, выделить память для строки согласно этого размера и прочитать данные в строковую переменную. Напротив, если старший бит поля <strong class='tag-b'>NameId</strong> сброшен то оно содержит числовой идентификатор ресурса (<strong class='tag-b'>RT_BITMAP</strong> в примере). Поле <strong class='tag-b'>OffsetToData</strong> имеет также двойную интерпретацию. Если старший бит установлен то это смещение (от начала ресурсов) до следующего уровня дерева ресурсов, т.е. до структуры <strong class='tag-b'>IMAGE_RESOURCE_DIRECTORY</strong>. Иначе - это смещение до структуры <strong class='tag-b'>IMAGE_RESOURCE_DATA_ENTRY</strong>:<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">Type IMAGE_RESOURCE_DATA_ENTRY</div><div class="code_line">&nbsp;&nbsp; &nbsp;OffsetToData &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Size &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;CodePage &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Reserved &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Наиболее важными для нас являются поля <strong class='tag-b'>OffsetToData</strong> and <strong class='tag-b'>Size</strong> которые содержат RVA и размер сырых данных ресурса. Теперь мы можем извлечь все данные из ресурсов любого PE файла.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='14' style='font-size:14pt;'><strong class='tag-b'><span class="tag-color tag-color-named" data-value="orange" style="color: orange">Компиляция.</span></strong></span></div><br>
<br>
Итак, когда мы начинаем компиляцию проекта то вызывается метод <strong class='tag-b'>Compile</strong> объекта класса <strong class='tag-b'>clsProject</strong>. Вначале упаковываются все элементы хранилища и команд в бинарный формат (<strong class='tag-b'>BinProject</strong>, <strong class='tag-b'>BinStorageListItem</strong>, и т.д.) и формируются таблица строк и файловая таблица. Строковая таблица сохраняется как набор строк разделенных нуль-терминалом. Я использую специальный класс <strong class='tag-b'>clsStream</strong> для безопасной работы с бинарными данными. Этот класс позволяет читать и писать любые данные или потоки в двоичный буфер, сжимать буфер. Я использую функцию <strong class='tag-b'>RtlCompressBuffer</strong> для сжатия потока которая использует LZ-сжатие. После упаковки и сжатия проверяется выходной формат файла. Поддерживаются 2 типа файлов: бинарный (сырые данные проекта) и исполняемый (загрузчик). Двоичный формат не интересен поэтому мы будем рассматривать исполняемый формат. Вначале извлекаются все ресурсы из главного исполняемого файла в трехуровневый каталог. Эта операция выполняется с помощью функции <strong class='tag-b'>ExtractResorces</strong>. Имена-идентификаторы сохраняются в строковом виде с префиксом &#39;#&#39;. Потом клонируется шаблон загрузчика в результирующий файл, начинается процесс модификации ресурсов в EXE файле используя функцию <strong class='tag-b'>BeginUpdateResource</strong>. После этого последовательно копируются все извлеченные ресурсы (<strong class='tag-b'>UpdateResource</strong>), двоичный проект и манифест (если нужно) в результирующий файл и применяются изменения функцией <strong class='tag-b'>EndUpdateResource</strong>. Опять повторюсь, бинарный проект сохраняется с именем <strong class='tag-b'>PROJECT</strong> и имеет тип <strong class='tag-b'>RT_DATA</strong>. В общем все.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='14' style='font-size:14pt;'><strong class='tag-b'><span class="tag-color tag-color-named" data-value="orange" style="color: orange">Загрузчик.</span></strong></span></div><br>
<br>
Итак. я думаю это наиболее интересная часть. Итак, нам нужно избегать использование рантайма. Как этого добится? Я дам некоторые правила:<ul class="tag-list"><li>Установить в качестве стартовой функции пользовательскую функцию;</li><li>Избегать любых объектов и классов в проекте;</li><li>Избегать непосредственных массивов. Массивы фиксированного размера в пользовательских типах не запрещены;</li><li>Избегать строковых переменных а также Variant/Object переменных. В некоторых случаях Currency/Date;</li><li>Избегать API функции задекларированые с помощью ключевого слова Declare;</li><li>Избегать VarPtr/StrPtr/ObjPtr и некоторые стандартные функции;</li><li>...</li><li>...</li></ul>Это неполный список ограничений, а во время выполнения шеллкода добавляются дополнительные ограничения.<br>
Итак, начнем. Для того чтобы избежать использования строковых переменных я храню все строковые переменные как Long указатели на строки. Существует проблема с загрузкой строк поскольку мы не можем обращаться к любой строке чтобы загрузить ее. Я решил использовать ресурсы в качестве хранилища строк и загружать их по числовому идентификатору. Таким образом мы можем хранить указатель в переменной Long без обращения к рантайму. Я использовал TLB (библиотеку типов) для всех API функций без атрибута <strong class='tag-b'>usesgetlasterror</strong> чтобы избежать объявление через Declare. Для установки стартовой функции я использую опции линкера. Стартовая функция в загрузчике - <strong class='tag-b'>Main</strong>. Обратите внимание, если в IDE выбрать стартовую функцию <strong class='tag-b'>Main</strong> на самом деле это не будет стартовой функцией приложения потому что VB6-скомпилированное приложение начинается с функции <strong class='tag-b'>__vbaS</strong> которая вызывает функцию <strong class='tag-b'>ThunRTMain</strong> из рантайма, которая инициализирует рантайм и поток. <br>
Загрузчик содержит три модуля:<ul class="tag-list"><li><strong class='tag-b'>modMain</strong> - стартовая функция и работа с хранилищем;</li><li><strong class='tag-b'>modConstants</strong> - работа со строковыми константами;</li><li><strong class='tag-b'>modLoader</strong> - загрузчик EXE файла.</li></ul>Когда загрузчик запустился выполняется функция <strong class='tag-b'>Main</strong>:<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">&#39; // Startup subroutine</div><div class="code_line">Sub Main()</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Load constants</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Not LoadConstants Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;MessageBox 0, GetString(MID_ERRORLOADINGCONST), 0, MB_ICONERROR Or MB_SYSTEMMODAL</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GoTo EndOfProcess</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Load project</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Not ReadProject Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;MessageBox 0, GetString(MID_ERRORREADINGPROJECT), 0, MB_ICONERROR Or MB_SYSTEMMODAL</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GoTo EndOfProcess</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Copying from storage</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Not CopyProcess Then GoTo EndOfProcess</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Execution process</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Not ExecuteProcess Then GoTo EndOfProcess</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // If main executable is not presented exit</div><div class="code_line">&nbsp;&nbsp; &nbsp;If ProjectDesc.storageDescriptor.iExecutableIndex = -1 Then GoTo EndOfProcess</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Run exe from memory</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Not RunProcess Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Error occrurs</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;MessageBox 0, GetString(MID_ERRORSTARTUPEXE), 0, MB_ICONERROR Or MB_SYSTEMMODAL</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">EndOfProcess:</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pProjectData Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;HeapFree GetProcessHeap(), HEAP_NO_SERIALIZE, pProjectData</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;ExitProcess 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Sub</div></ol></div></div></div></div><br>
Вначале вызывается функция <strong class='tag-b'>LoadConstants</strong> для того чтобы загрузить все необходимые константы из ресурсов:<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">&#39; // modConstants.bas - main module for loading constants</div><div class="code_line">&#39; // © Krivous Anatoly Anatolevich (The trick), 2016</div><div class="code_line">&nbsp;</div><div class="code_line">Option Explicit</div><div class="code_line">&nbsp;</div><div class="code_line">Public Enum MessagesID</div><div class="code_line">&nbsp;&nbsp; &nbsp;MID_ERRORLOADINGCONST = 100 &nbsp; &nbsp; &#39; // Errors</div><div class="code_line">&nbsp;&nbsp; &nbsp;MID_ERRORREADINGPROJECT = 101 &nbsp; &#39;</div><div class="code_line">&nbsp;&nbsp; &nbsp;MID_ERRORCOPYINGFILE = 102 &nbsp; &nbsp; &nbsp;&#39;</div><div class="code_line">&nbsp;&nbsp; &nbsp;MID_ERRORWIN32 = 103 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39;</div><div class="code_line">&nbsp;&nbsp; &nbsp;MID_ERROREXECUTELINE = 104 &nbsp; &nbsp; &nbsp;&#39;</div><div class="code_line">&nbsp;&nbsp; &nbsp;MID_ERRORSTARTUPEXE = 105 &nbsp; &nbsp; &nbsp; &#39;</div><div class="code_line">&nbsp;&nbsp; &nbsp;PROJECT = 200 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#39; // Project resource ID</div><div class="code_line">&nbsp;&nbsp; &nbsp;API_LIB_KERNEL32 = 300 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Library names</div><div class="code_line">&nbsp;&nbsp; &nbsp;API_LIB_NTDLL = 350 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#39;</div><div class="code_line">&nbsp;&nbsp; &nbsp;API_LIB_USER32 = 400 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39;</div><div class="code_line">&nbsp;&nbsp; &nbsp;MSG_LOADER_ERROR = 500</div><div class="code_line">End Enum</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Paths</div><div class="code_line">&nbsp;</div><div class="code_line">Public pAppPath &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Path to application</div><div class="code_line">Public pSysPath &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Path to System32</div><div class="code_line">Public pTmpPath &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Path to Temp</div><div class="code_line">Public pWinPath &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Path to Windows</div><div class="code_line">Public pDrvPath &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Path to system drive</div><div class="code_line">Public pDtpPath &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Path to desktop</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Substitution constants</div><div class="code_line">&nbsp;</div><div class="code_line">Public pAppRepl &nbsp;As Long</div><div class="code_line">Public pSysRepl &nbsp;As Long</div><div class="code_line">Public pTmpRepl &nbsp;As Long</div><div class="code_line">Public pWinRepl &nbsp;As Long</div><div class="code_line">Public pDrvRepl &nbsp;As Long</div><div class="code_line">Public pDtpRepl &nbsp;As Long</div><div class="code_line">Public pStrNull &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // {text}</div><div class="code_line">&nbsp;</div><div class="code_line">Public hInstance &nbsp; &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &#39; // Base address</div><div class="code_line">Public lpCmdLine &nbsp; &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &#39; // Command line</div><div class="code_line">Public SI &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As STARTUPINFO &nbsp;&#39; // Startup parameters</div><div class="code_line">Public LCID &nbsp; &nbsp; &nbsp; &nbsp; As Long &nbsp; &nbsp; &nbsp; &nbsp; &#39; // LCID</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Load constants</div><div class="code_line">Function LoadConstants() As Boolean</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lSize &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pBuf &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim index &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ctl &nbsp; &nbsp; As tagINITCOMMONCONTROLSEX</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Load windows classes</div><div class="code_line">&nbsp;&nbsp; &nbsp;ctl.dwSize = Len(ctl)</div><div class="code_line">&nbsp;&nbsp; &nbsp;ctl.dwICC = &amp;H3FFF&amp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;InitCommonControlsEx ctl</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get startup parameters</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetStartupInfo SI</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get command line</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpCmdLine = GetCommandLine()</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get base address</div><div class="code_line">&nbsp;&nbsp; &nbsp;hInstance = GetModuleHandle(ByVal 0&amp;)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get LCID</div><div class="code_line">&nbsp;&nbsp; &nbsp;LCID = GetUserDefaultLCID()</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Alloc memory for strings</div><div class="code_line">&nbsp;&nbsp; &nbsp;pBuf = SysAllocStringLen(0, MAX_PATH)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pBuf = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get path to process file name</div><div class="code_line">&nbsp;&nbsp; &nbsp;If GetModuleFileName(hInstance, pBuf, MAX_PATH) = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Leave only directory</div><div class="code_line">&nbsp;&nbsp; &nbsp;PathRemoveFileSpec pBuf</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Save path</div><div class="code_line">&nbsp;&nbsp; &nbsp;pAppPath = SysAllocString(pBuf)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get Windows folder</div><div class="code_line">&nbsp;&nbsp; &nbsp;If GetWindowsDirectory(pBuf, MAX_PATH) = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;pWinPath = SysAllocString(pBuf)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get System32 folder</div><div class="code_line">&nbsp;&nbsp; &nbsp;If GetSystemDirectory(pBuf, MAX_PATH) = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;pSysPath = SysAllocString(pBuf)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get Temp directory</div><div class="code_line">&nbsp;&nbsp; &nbsp;If GetTempPath(MAX_PATH, pBuf) = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;pTmpPath = SysAllocString(pBuf)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get system drive</div><div class="code_line">&nbsp;&nbsp; &nbsp;PathStripToRoot pBuf</div><div class="code_line">&nbsp;&nbsp; &nbsp;pDrvPath = SysAllocString(pBuf)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get desktop path</div><div class="code_line">&nbsp;&nbsp; &nbsp;If SHGetFolderPath(0, CSIDL_DESKTOPDIRECTORY, 0, SHGFP_TYPE_CURRENT, pBuf) Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;pDtpPath = SysAllocString(pBuf)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Load wildcards</div><div class="code_line">&nbsp;&nbsp; &nbsp;For index = 1 To 6</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If LoadString(hInstance, index, pBuf, MAX_PATH) = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Select Case index</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Case 1: pAppRepl = SysAllocString(pBuf)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Case 2: pSysRepl = SysAllocString(pBuf)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Case 3: pTmpRepl = SysAllocString(pBuf)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Case 4: pWinRepl = SysAllocString(pBuf)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Case 5: pDrvRepl = SysAllocString(pBuf)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Case 6: pDtpRepl = SysAllocString(pBuf)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End Select</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // vbNullChar</div><div class="code_line">&nbsp;&nbsp; &nbsp;pStrNull = SysAllocStringLen(0, 0)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Success</div><div class="code_line">&nbsp;&nbsp; &nbsp;LoadConstants = True</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">CleanUp:</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pBuf Then SysFreeString pBuf</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Obtain string from resource (it should be less or equal MAX_PATH)</div><div class="code_line">Public Function GetString( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ByVal ID As MessagesID) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetString = SysAllocStringLen(0, MAX_PATH)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If GetString Then</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If LoadString(hInstance, ID, GetString, MAX_PATH) = 0 Then SysFreeString GetString: GetString = 0: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If SysReAllocString(GetString, GetString) = 0 Then SysFreeString GetString: GetString = 0: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Функция <strong class='tag-b'>LoadConstants</strong> загружает все необходимые переменные и строки (hInstance, LCID, командная строка, подстановочные символы, пути по умолчанию, и т.д.). Все строки сохраняются в формате UNICODE-BSTR. Функция <strong class='tag-b'>GetString</strong> загружает строку из ресурсов по ее идентификатору. Перечисление <strong class='tag-b'>MessagesID</strong> содержит некоторые строковые идентификаторы  нужные для работы программы (сообщения об ошибках, имена библиотек, и.т.д.). Когда все константы загрузятся вызывается функция <strong class='tag-b'>ReadProject</strong> которая загружает проект:<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">&#39; // Load project</div><div class="code_line">Function ReadProject() As Boolean</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim hResource &nbsp; &nbsp; &nbsp; As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim hMememory &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lResSize &nbsp; &nbsp; &nbsp; &nbsp;As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim pRawData &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim status &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim pUncompressed &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lUncompressSize As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim lResultSize &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tmpStorageItem &nbsp;As BinStorageListItem: &nbsp;Dim tmpExecuteItem &nbsp;As BinExecListItem</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pLocalBuffer &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Load resource</div><div class="code_line">&nbsp;&nbsp; &nbsp;hResource = FindResource(hInstance, GetString(PROJECT), RT_RCDATA)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hResource = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;hMememory = LoadResource(hInstance, hResource)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hMememory = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;lResSize = SizeofResource(hInstance, hResource)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lResSize = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;pRawData = LockResource(hMememory)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pRawData = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;pLocalBuffer = HeapAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE, lResSize)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pLocalBuffer = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Copy to local buffer</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory ByVal pLocalBuffer, ByVal pRawData, lResSize</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Set default size</div><div class="code_line">&nbsp;&nbsp; &nbsp;lUncompressSize = lResSize * 2</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Do decompress...</div><div class="code_line">&nbsp;&nbsp; &nbsp;Do</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If pUncompressed Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pUncompressed = HeapReAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE, ByVal pUncompressed, lUncompressSize)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pUncompressed = HeapAlloc(GetProcessHeap(), HEAP_NO_SERIALIZE, lUncompressSize)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;status = RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pUncompressed, lUncompressSize, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal pLocalBuffer, lResSize, lResultSize)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lUncompressSize = lUncompressSize * 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Loop While status = STATUS_BAD_COMPRESSION_BUFFER</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;pProjectData = pUncompressed</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If status Then GoTo CleanUp</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Validation check</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lResultSize &#60; LenB(ProjectDesc) Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Copy descriptor</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory ProjectDesc, ByVal pProjectData, LenB(ProjectDesc)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Check all members</div><div class="code_line">&nbsp;&nbsp; &nbsp;If ProjectDesc.dwSizeOfStructure &#60;&#62; Len(ProjectDesc) Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;If ProjectDesc.storageDescriptor.dwSizeOfStructure &#60;&#62; Len(ProjectDesc.storageDescriptor) Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;If ProjectDesc.storageDescriptor.dwSizeOfItem &#60;&#62; Len(tmpStorageItem) Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;If ProjectDesc.execListDescriptor.dwSizeOfStructure &#60;&#62; Len(ProjectDesc.execListDescriptor) Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;If ProjectDesc.execListDescriptor.dwSizeOfItem &#60;&#62; Len(tmpExecuteItem) Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Initialize pointers</div><div class="code_line">&nbsp;&nbsp; &nbsp;pStoragesTable = pProjectData + ProjectDesc.dwSizeOfStructure</div><div class="code_line">&nbsp;&nbsp; &nbsp;pExecutesTable = pStoragesTable + ProjectDesc.storageDescriptor.dwSizeOfItem * ProjectDesc.storageDescriptor.dwNumberOfItems</div><div class="code_line">&nbsp;&nbsp; &nbsp;pFilesTable = pExecutesTable + ProjectDesc.execListDescriptor.dwSizeOfItem * ProjectDesc.execListDescriptor.dwNumberOfItems</div><div class="code_line">&nbsp;&nbsp; &nbsp;pStringsTable = pFilesTable + ProjectDesc.dwFileTableLen</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Check size</div><div class="code_line">&nbsp;&nbsp; &nbsp;If (pStringsTable + ProjectDesc.dwStringsTableLen - pProjectData) &#60;&#62; lResultSize Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Success</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReadProject = True</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">CleanUp:</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pLocalBuffer Then HeapFree GetProcessHeap(), HEAP_NO_SERIALIZE, pLocalBuffer</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Not ReadProject And pProjectData Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;HeapFree GetProcessHeap(), HEAP_NO_SERIALIZE, pProjectData</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Как можно увидеть я использую кучу процесса вместо массивов. Вначале загружается ресурс с проектом - <strong class='tag-b'>PROJECT</strong> и копируется в кучу, затем производится декомпрессия используя функцию <strong class='tag-b'>RtlDecompressBuffer</strong>. Эта функция не возвращает необходимый размер буфера поэтому мы пытаемся распаковать буфер увеличивая выходной размер буфера пока декомпрессия не будет успешно выполнена. После декомпрессии проверяются все параметры и инициализируются глобальные указатели проекта.<br>
Если проект успешно загружен то вызывается функция <strong class='tag-b'>CopyProcess</strong> которая распаковывает все файлы из хранилища, согласно данным проекта:<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">&#39; // Copying process</div><div class="code_line">Function CopyProcess() As Boolean</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim bItem &nbsp; &nbsp; &nbsp; As BinStorageListItem: &nbsp;Dim index &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pPath &nbsp; &nbsp; &nbsp; As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim dwWritten &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim msg &nbsp; &nbsp; &nbsp; &nbsp; As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim lStep &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim isError &nbsp; &nbsp; As Boolean: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Dim pItem &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pErrMsg &nbsp; &nbsp; As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim pTempString As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Set pointer</div><div class="code_line">&nbsp;&nbsp; &nbsp;pItem = pStoragesTable</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Go thru file list</div><div class="code_line">&nbsp;&nbsp; &nbsp;For index = 0 To ProjectDesc.storageDescriptor.dwNumberOfItems - 1</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Copy file descriptor</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CopyMemory bItem, ByVal pItem, Len(bItem)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Next item</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pItem = pItem + ProjectDesc.storageDescriptor.dwSizeOfItem</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // If it is not main executable</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If index &#60;&#62; ProjectDesc.storageDescriptor.iExecutableIndex Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Normalize path</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pPath = NormalizePath(pStringsTable + bItem.ofstDestPath, pStringsTable + bItem.ofstFileName)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Error occurs</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If pPath = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pErrMsg = GetString(MID_ERRORWIN32)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;MessageBox 0, pErrMsg, 0, MB_ICONERROR Or MB_SYSTEMMODAL</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim hFile &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim disp &nbsp; &nbsp;As CREATIONDISPOSITION</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Set overwrite flags</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If bItem.dwFlags And FF_REPLACEONEXIST Then disp = CREATE_ALWAYS Else disp = CREATE_NEW</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Set number of subroutine</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;lStep = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Run subroutines</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Do</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Disable error flag</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;isError = False</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Free string</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If pErrMsg Then SysFreeString pErrMsg: pErrMsg = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Choose subroutine</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Select Case lStep</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Case 0 &nbsp;&#39; // 0. Create folder</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If Not CreateSubdirectories(pPath) Then isError = True</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Case 1 &nbsp;&#39; // 1. Create file</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hFile = CreateFile(pPath, FILE_GENERIC_WRITE, 0, ByVal 0&amp;, disp, FILE_ATTRIBUTE_NORMAL, 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If hFile = INVALID_HANDLE_VALUE Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If GetLastError = ERROR_FILE_EXISTS Then Exit Do</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;isError = True</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Case 2 &nbsp;&#39; // 2. Copy data to file</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If WriteFile(hFile, ByVal pFilesTable + bItem.ofstBeginOfData, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bItem.dwSizeOfFile, dwWritten, ByVal 0&amp;) = 0 Then isError = True</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If dwWritten &#60;&#62; bItem.dwSizeOfFile Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;isError = True</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CloseHandle hFile: hFile = INVALID_HANDLE_VALUE</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End Select</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // If error occurs show notification (retry, abort, ignore)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If isError Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Ignore error</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If bItem.dwFlags And FF_IGNOREERROR Then Exit Do</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pTempString = GetString(MID_ERRORCOPYINGFILE)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pErrMsg = StrCat(pTempString, pPath)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Cleaning</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SysFreeString pTempString: pTempString = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Select Case MessageBox(0, pErrMsg, 0, MB_ICONERROR Or MB_SYSTEMMODAL Or MB_CANCELTRYCONTINUE)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Case MESSAGEBOXRETURN.IDCONTINUE: Exit Do</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Case MESSAGEBOXRETURN.IDTRYAGAIN</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Case Else: &nbsp;GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End Select</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Else: lStep = lStep + 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Loop While lStep &#60;= 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If hFile &#60;&#62; INVALID_HANDLE_VALUE Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CloseHandle hFile: hFile = INVALID_HANDLE_VALUE</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Cleaning</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SysFreeString pPath: pPath = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Success</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyProcess = True</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">CleanUp:</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pTempString Then SysFreeString pTempString</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pErrMsg Then SysFreeString pErrMsg</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pPath Then SysFreeString pPath</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hFile &#60;&#62; INVALID_HANDLE_VALUE Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CloseHandle hFile</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;hFile = INVALID_HANDLE_VALUE</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Эта процедура проходит по всем элементам хранилища и распаковывает их одна за одной исключая главный исполняемый файл. Функция <strong class='tag-b'>NormalizePath</strong> заменяет подстановочные знаки на реальные пути. Также существует функция <strong class='tag-b'>CreateSubdirectories</strong> которая создает промежуточные директории (если необходимо) по переданному в качестве параметра пути. Затем вызывается функция <strong class='tag-b'>CreateFile</strong> для создания файла затем через <strong class='tag-b'>WriteFile</strong> данные пишутся в файл. Если происходит ошибка то выводится стандартное сообщение с предложением повторить, отменить или игнорировать.<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">&#39; // Create all subdirectories by path</div><div class="code_line">Function CreateSubdirectories( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ByVal pPath As Long) As Boolean</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pComponent As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tChar &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Pointer to first char</div><div class="code_line">&nbsp;&nbsp; &nbsp;pComponent = pPath</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Go thru path components</div><div class="code_line">&nbsp;&nbsp; &nbsp;Do</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Get next component</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pComponent = PathFindNextComponent(pComponent)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Check if end of line</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CopyMemory tChar, ByVal pComponent, 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If tChar = 0 Then Exit Do</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Write null-terminator</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CopyMemory ByVal pComponent - 2, 0, 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Check if path exists</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If PathIsDirectory(pPath) = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Create folder</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If CreateDirectory(pPath, ByVal 0&amp;) = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Error</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CopyMemory ByVal pComponent - 2, &amp;H5C, 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Restore path delimiter</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CopyMemory ByVal pComponent - 2, &amp;H5C, 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Loop</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Success</div><div class="code_line">&nbsp;&nbsp; &nbsp;CreateSubdirectories = True</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Get normalize path (replace wildcards, append file name)</div><div class="code_line">Function NormalizePath( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ByVal pPath As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ByVal pTitle As Long) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lPathLen &nbsp; &nbsp;As Long: &nbsp; &nbsp;Dim lRelacerLen As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lTitleLen &nbsp; As Long: &nbsp; &nbsp;Dim pRelacer &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lTotalLen &nbsp; As Long: &nbsp; &nbsp;Dim lPtr &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pTempString As Long: &nbsp; &nbsp;Dim pRetString &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Determine wildcard</div><div class="code_line">&nbsp;&nbsp; &nbsp;Select Case True</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case IntlStrEqWorker(0, pPath, pAppRepl, 5): pRelacer = pAppPath</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case IntlStrEqWorker(0, pPath, pSysRepl, 5): pRelacer = pSysPath</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case IntlStrEqWorker(0, pPath, pTmpRepl, 5): pRelacer = pTmpPath</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case IntlStrEqWorker(0, pPath, pWinRepl, 5): pRelacer = pWinPath</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case IntlStrEqWorker(0, pPath, pDrvRepl, 5): pRelacer = pDrvPath</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case IntlStrEqWorker(0, pPath, pDtpRepl, 5): pRelacer = pDtpPath</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case Else: pRelacer = pStrNull</div><div class="code_line">&nbsp;&nbsp; &nbsp;End Select</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get string size</div><div class="code_line">&nbsp;&nbsp; &nbsp;lPathLen = lstrlen(ByVal pPath)</div><div class="code_line">&nbsp;&nbsp; &nbsp;lRelacerLen = lstrlen(ByVal pRelacer)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Skip wildcard</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lRelacerLen Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pPath = pPath + 5 * 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lPathLen = lPathLen - 5</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pTitle Then lTitleLen = lstrlen(ByVal pTitle)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Get length all strings</div><div class="code_line">&nbsp;&nbsp; &nbsp;lTotalLen = lPathLen + lRelacerLen + lTitleLen</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Check overflow (it should be les or equal MAX_PATH)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lTotalLen &#62; MAX_PATH Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Create string</div><div class="code_line">&nbsp;&nbsp; &nbsp;pTempString = SysAllocStringLen(0, MAX_PATH)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pTempString = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Copy</div><div class="code_line">&nbsp;&nbsp; &nbsp;lstrcpyn ByVal pTempString, ByVal pRelacer, lRelacerLen + 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;lstrcat ByVal pTempString, ByVal pPath</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // If title is presented append</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pTitle Then</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Error</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If PathAddBackslash(pTempString) = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Copy file name</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lstrcat ByVal pTempString, ByVal pTitle</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Alloc memory for translation relative path to absolute</div><div class="code_line">&nbsp;&nbsp; &nbsp;pRetString = SysAllocStringLen(0, MAX_PATH)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pRetString = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Normalize</div><div class="code_line">&nbsp;&nbsp; &nbsp;If PathCanonicalize(pRetString, pTempString) = 0 Then GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;NormalizePath = pRetString</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">CleanUp:</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pTempString Then SysFreeString pTempString</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pRetString &#60;&#62; 0 And NormalizePath = 0 Then SysFreeString pRetString</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Concatenation strings</div><div class="code_line">Function StrCat( _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ByVal pStringDest As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ByVal pStringAppended As Long) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim l1 As Long, l2 As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;l1 = lstrlen(ByVal pStringDest): l2 = lstrlen(ByVal pStringAppended)</div><div class="code_line">&nbsp;&nbsp; &nbsp;StrCat = SysAllocStringLen(0, l1 + l2)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If StrCat = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;lstrcpyn ByVal StrCat, ByVal pStringDest, l1 + 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;lstrcat ByVal StrCat, ByVal pStringAppended</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
После извлечения файлов вызывается функция <strong class='tag-b'>ExecuteProcess</strong> которая запускает выполнение команд используя функцию <strong class='tag-b'>ShellExecuteEx</strong>:<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">&#39; // Execution command process</div><div class="code_line">Function ExecuteProcess() As Boolean</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim index &nbsp; &nbsp; &nbsp; As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim bItem &nbsp; &nbsp; &nbsp; As BinExecListItem</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pPath &nbsp; &nbsp; &nbsp; As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim pErrMsg &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim shInfo &nbsp; &nbsp; &nbsp;As SHELLEXECUTEINFO: &nbsp; &nbsp;Dim pTempString As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pItem &nbsp; &nbsp; &nbsp; As Long: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim status &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Set pointer and size</div><div class="code_line">&nbsp;&nbsp; &nbsp;shInfo.cbSize = Len(shInfo)</div><div class="code_line">&nbsp;&nbsp; &nbsp;pItem = pExecutesTable</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Go thru all items</div><div class="code_line">&nbsp;&nbsp; &nbsp;For index = 0 To ProjectDesc.execListDescriptor.dwNumberOfItems - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Copy item</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CopyMemory bItem, ByVal pItem, ProjectDesc.execListDescriptor.dwSizeOfItem</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Set pointer to next item</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pItem = pItem + ProjectDesc.execListDescriptor.dwSizeOfItem</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Normalize path</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pPath = NormalizePath(pStringsTable + bItem.ofstFileName, 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Fill SHELLEXECUTEINFO</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;shInfo.lpFile = pPath</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;shInfo.lpParameters = pStringsTable + bItem.ofstParameters</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;shInfo.fMask = SEE_MASK_NOCLOSEPROCESS Or SEE_MASK_FLAG_NO_UI</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;shInfo.nShow = SW_SHOWDEFAULT</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Performing...</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;status = ShellExecuteEx(shInfo)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // If error occurs show notification (retry, abort, ignore)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Do Until status</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If pErrMsg Then SysFreeString pErrMsg: pErrMsg = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; // Ignore error</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If bItem.dwFlags And EF_IGNOREERROR Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit Do</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pTempString = GetString(MID_ERROREXECUTELINE)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pErrMsg = StrCat(pTempString, pPath)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SysFreeString pTempString: pTempString = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Select Case MessageBox(0, pErrMsg, 0, MB_ICONERROR Or MB_SYSTEMMODAL Or MB_CANCELTRYCONTINUE)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Case MESSAGEBOXRETURN.IDCONTINUE: Exit Do</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Case MESSAGEBOXRETURN.IDTRYAGAIN</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Case Else: GoTo CleanUp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End Select</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;status = ShellExecuteEx(shInfo)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Loop</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; // Wait for process terminaton</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;WaitForSingleObject shInfo.hProcess, INFINITE</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CloseHandle shInfo.hProcess</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; // Success</div><div class="code_line">&nbsp;&nbsp; &nbsp;ExecuteProcess = True</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">CleanUp:</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pTempString Then SysFreeString pTempString</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pErrMsg Then SysFreeString pErrMsg</div><div class="code_line">&nbsp;&nbsp; &nbsp;If pPath Then SysFreeString pPath</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div>]]></description>
        <author>TheTrik</author>
        <category>Visual Basic: Общие вопросы</category>
      </item>
	
      </channel>
      </rss>
	