8

I tried to write a peloader. I first load the executable image and all it's dependent dlls(include kernel32.dll and ntdll.dll) into memory, process all import address table, rewrite all data which need relocation.

Then I call all image's EntryPoint in order. I get the return code 0 from ntdll.dll's EntryPoint, but kernel32.dll returns 0xC0000000. When I tried to call the executable image's EntryPoint, the program crashed.

I know the windows system already load ntdll.dll and kernel32.dll into process memory when the process is created. My question is how can I load another copy of ntdll.dll and kernel32.dll into memory, and link my module to the copy ones.

I make an experiment: 1. copy ntdll.dll -> a.dll

  1. copy kernel32.dll -> b.dll
  2. modify PE image file b.dll to make it not depends on ntdll.dll but a.dll
  3. write a simple program a.exe, and modify the PE image file a.exe to make it not depends on kernel32.dll but b.dll
  4. run a.exe, and the program crashed

Is it possible to make a.exe run correctly?

It's my first question on stack overflow, sorry for my poor english. Thanks.

cnzjnblxj
  • 81
  • 1
  • 3
  • Is the code available? I've recently been thinking about doing the same. As for your question, it probably fails for the same reason it fails when you try to call ntdll!LdrLoadDll for kernel32 from a native application -- kernel32 tries to contact csrss and fails. – avakar Sep 20 '11 at 07:47
  • I add too many debug info in my code, so it's a really dirty one. I'll refactor my code later if I can solve the problem. – cnzjnblxj Sep 20 '11 at 08:16
  • You might also want to fetch reactos sources http://www.reactos.org/en/index.html and take a look at how they implement CreateProcess. Note that after creating the process object they inform csrss about the new process. Only then they create the new thread. They also don't call entry points, instead they dispatch through a kernel32 thunk. Windows 7 kernel starts the first thread at ntdll!__RtlUserThreadStart, which takes care of initialization and ultimately calls the executable entry point. – avakar Sep 20 '11 at 08:25
  • Thanks a lot. It's really kind of you. I'll take your advice and check my situation. Thank you very much. – cnzjnblxj Sep 20 '11 at 08:33
  • 1
    if you'd eventually want to put your code on github or somewhere and leave a link here, I might be interested in looking at it. – avakar Sep 20 '11 at 08:34

3 Answers3

4

I don't think you can do this. The kernel32.dll and ntdll.dll, AFAIK are not relocatable. That is, MS removed the relocation information from them, because, as they are already loaded in every process, their assigned addresses are always available, by design.

So, if you try to load them into a different address, well, they'll crash. You could theoretically try to rebuild the relocation information for them... but I wouldn't bet on it.

My question in turn is: why cannot you use the preloaded kernel32/ntdll? Why do you feel that you need private copies? As I see it, you should consider them the system API, and so leave them alone.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • 1
    ntdll.dll and kernel32.dll DO have relocation information. The PE image file contains the "Base Relocation Table Address and Size" directory entry. So I think this is not the point. You can copy ntdll.dll -> a.dll, and use LoadLibrary("a.dll") to load it. You can get a handle different from ntdll.dll. One may inject a dll into my process and hook my system calls, so I may get wrong hardware info and so on. My purpose to load system dlls by myself is just one way to prevent(or just make it not too easy) this kind of hook. Sorry for my poor english. – cnzjnblxj Sep 20 '11 at 08:59
  • 1
    that isn't entirely true, kernel32 and ntdll can relocate, but only per system reboot (this is from ASLR) – Necrolis Sep 20 '11 at 09:01
  • Oh, you are right, in my XP they do have a .reloc section full of entries... The thing is that I kind of remember them not having it, maybe in an old windows version. – rodrigo Sep 20 '11 at 14:21
0

In visual studio put in the project properties linker->input->Ignore All default libraries to yes. Then in c++->Code Generation->Basic Runtime Check to default (to avoid linking in __RTC_*. Then in linker->Advanced->Entry Point you specify an function in your project you want to be called when the program is started.

Build everything and you should have a program that isn't linked to any library, including the c-runtime.

0

If you wish to use your own version of ntdll.dll (a.dll) in your code then you can read the dll using Readfile() and parse the PE structures to use in your code. for eg: you may parse the Export Name Table, Export ordinal table and Export address table to find pointers to the exported functions and use the same in your executable.

Saurabh
  • 295
  • 3
  • 12