Как запустить PE-образ без связывания kernel32.dll и ntdll.dll

Пробовал писать пелоадер. Сначала я загружаю исполняемый образ и все зависимые от него dll (включая kernel32.dll и ntdll.dll) в память, обрабатываю всю таблицу адресов импорта, перезаписываю все данные, которые требуют перемещения.

Затем я вызываю EntryPoint всех изображений по порядку. Я получаю код возврата 0 из EntryPoint ntdll.dll, но kernel32.dll возвращает 0xC0000000. Когда я попытался вызвать EntryPoint исполняемого образа, программа вылетела.

Я знаю, что система Windows уже загружает ntdll.dll и kernel32.dll в память процесса при его создании. Мой вопрос заключается в том, как я могу загрузить в память еще одну копию ntdll.dll и kernel32.dll и связать свой модуль с копиями.

Делаю эксперимент: 1. копируем ntdll.dll -> a.dll

  1. скопировать kernel32.dll -> b.dll
  2. изменить файл PE-образа b.dll, чтобы он не зависел от ntdll.dll, а от a.dll
  3. напишите простую программу a.exe и измените файл образа PE a.exe, чтобы он не зависел от kernel32.dll, а b.dll
  4. запустить a.exe, и программа разбилась

Можно ли заставить .exe работать корректно?

Это мой первый вопрос о переполнении стека, извините за мой плохой английский. Спасибо.


person cnzjnblxj    schedule 20.09.2011    source источник
comment
Доступен ли код? Я недавно думал о том, чтобы сделать то же самое. Что касается вашего вопроса, он, вероятно, не работает по той же причине, что и при попытке вызвать ntdll!LdrLoadDll для kernel32 из собственного приложения - kernel32 пытается связаться с csrss и терпит неудачу.   -  person avakar    schedule 20.09.2011
comment
Я добавляю слишком много отладочной информации в свой код, так что он действительно грязный. Я отрефакторю свой код позже, если смогу решить проблему.   -  person cnzjnblxj    schedule 20.09.2011
comment
Вы также можете получить источники reactos reactos.org/en/index.html и взгляните на то, как они реализуют CreateProcess. Обратите внимание, что после создания объекта процесса они информируют csrss о новом процессе. Только после этого они создают новый поток. Они также не вызывают точки входа, вместо этого они отправляются через преобразователь ядра 32. Ядро Windows 7 запускает первый поток в ntdll!__RtlUserThreadStart, который заботится об инициализации и в конечном итоге вызывает точку входа исполняемого файла.   -  person avakar    schedule 20.09.2011
comment
Большое спасибо. Это очень мило с твоей стороны. Воспользуюсь вашим советом и проверю свою ситуацию. Большое Вам спасибо.   -  person cnzjnblxj    schedule 20.09.2011
comment
если вы в конечном итоге захотите разместить свой код на github или где-нибудь еще и оставить ссылку здесь, мне может быть интересно взглянуть на него.   -  person avakar    schedule 20.09.2011


Ответы (3)


Я не думаю, что вы можете сделать это. Ядро32.dll и ntdll.dll, насколько я знаю, не перемещаются. То есть MS удалила из них информацию о релокации, потому что, поскольку они уже загружены в каждом процессе, назначенные им адреса всегда доступны по замыслу.

Итак, если вы попытаетесь загрузить их по другому адресу, они рухнут. Теоретически можно попытаться восстановить для них информацию о перемещении... но я бы не стал на это ставить.

Мой вопрос, в свою очередь, таков: почему вы не можете использовать предварительно загруженный kernel32/ntdll? Почему вы считаете, что вам нужны частные копии? Как мне видится, вы должны считать их системным API, а так оставить их в покое.

person rodrigo    schedule 20.09.2011
comment
ntdll.dll и kernel32.dll содержат информацию о перемещении. Файл образа PE содержит запись каталога Base Relocation Table Address and Size. Так что думаю дело не в этом. Вы можете скопировать ntdll.dll -> a.dll и использовать LoadLibrary(a.dll) для его загрузки. Вы можете получить дескриптор, отличный от ntdll.dll. Можно внедрить dll в мой процесс и перехватить мои системные вызовы, поэтому я могу получить неверную информацию об оборудовании и так далее. Моя цель загрузить системные dll самостоятельно - это только один из способов предотвратить (или просто сделать это не слишком простым) такого рода хуков. Извините за мой плохой английский. - person cnzjnblxj; 20.09.2011
comment
это не совсем так, kernel32 и ntdll могут перемещаться, но только при перезагрузке системы (это из ASLR) - person Necrolis; 20.09.2011
comment
О, вы правы, в моей XP у них есть раздел .reloc, полный записей ... Дело в том, что я как бы помню, что у них его не было, может быть, в старой версии Windows. - person rodrigo; 20.09.2011

В Visual Studio в свойствах проекта поставьте linker->input->Ignore All default libraries на yes. Затем в c++->Code Generation->Basic Runtime Check по умолчанию (чтобы избежать привязки в __RTC_*. Затем в linker->Advanced->Entry Point вы указываете функцию в своем проекте, которую вы хотите вызывать при запуске программы.

Соберите все, и у вас должна быть программа, которая не связана ни с одной библиотекой, включая среду выполнения c.

person Community    schedule 20.09.2011
comment
Я не так четко описал вопрос, но все равно спасибо. - person cnzjnblxj; 20.09.2011

Если вы хотите использовать свою собственную версию ntdll.dll (a.dll) в своем коде, вы можете прочитать dll с помощью Readfile() и проанализировать PE-структуры для использования в своем коде. например: вы можете проанализировать таблицу имен экспорта, порядковую таблицу экспорта и таблицу адресов экспорта, чтобы найти указатели на экспортированные функции и использовать их в своем исполняемом файле.

person Saurabh    schedule 03.03.2012