HOWTO - Building without Import Libraries

mmozeiko

You'll need to change win32_pe structure to support 32-bit header. And change code line that gets TEB structure, on 32-bit its done differently. Otherwise the logic stays the same.


Could you show me exactly how it's done sir? I just don't have any experience on the matter and there's hardly any information on this topic... I need to see how it all works and then I'll be able to start analyzing it thoroughly.
By the way, I've used your splendid guide and disabled CRT successfully, would that require to make any additional changes other than what you've mentioned?
Thank you very much in advance!
This will return TEB pointer on 32-bit Windows:
1
__readfsdword(0x18);


Also PEB in TEB is at offset 0x30.
I don't remember structure of PEB, but its layout probably also is different (to get LoaderData member). Check the structure declaration.

For win32_pe structure check this link: https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format
Pay attention to "Optional Header (Image Only)".

Using or not using CRT is completely orthogonal to this. It does not affect this "no-imports" hack.

Btw, its fun to do this, but I suggest avoiding this in real production code (the one you want to give to other people). Many security software or anti-virus'es doesn't like executables that do not have any imports and may flag your exe as very suspicious. Link to kernel32.dll to get LoadLibrary & GetProcAddress, and there's no need for this hackery.

Edited by Mārtiņš Možeiko on
Thank you very much for this valuable information my man!
Before I dig in, I just want to know one more little thing. At the beginning of your guide on how to avoid using CRT, you said this exact thing: "...you should never return from WinMainCRTStartup function, so I am calling ExitProcess function at end of it." - this raises many questions within me now that I moved to this guide.

First of all, why should I never return from WinMainCRTStartup? It seems to be running just the same if I put a return in their instead.
Secondly, does this mean I have to implement ExitProcess myself if I'm about to get rid of the kernel32.dll import? And if so, how would I go about it?
You don't implement ExitProcess function yourself. You get it from kernel32.dll just like any other function (CreateFile, ReadFile, etc...) and then call it. It is Windows function, not C runtime function.

Edited by Mārtiņš Možeiko on
Thanks a bunch you guys, I'm almost there!
I've managed to find and load successfully the kerne32.dll as well as all the other dll's, however, I'm having a problem in the following line:

1
windowClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);


The reason I know that this line causes a problem is because without it everything works fine but if I put it back in, the RegisterClassA returns the 87th error code which stands for "ERROR_INVALID_PARAMETER".
Does anyone know what's the deal here?
Why do you this is the line that makes RegisterClassA to fail?
Have you checked return value of GetStockObject? Even if it fails and returns NULL, that is completely valid value for hbrBackground member.
My guess is that you have set some other member to invalid value.
mmozeiko

Why do you this is the line that makes RegisterClassA to fail?
Have you checked return value of GetStockObject? Even if it fails and returns NULL, that is completely valid value for hbrBackground member.
My guess is that you have set some other member to invalid value.


If I had set some other member to invalid value then the program wouldn't run even without setting the hbrBackground, wouldn't it?
I haven't touched any other member except hInstance which gets the kernel32 module like so:

1
2
3
4
5
6
7
void __stdcall WinMainCRTStartup() {
	HMODULE Kernel32 = GetKernel32Module();
	DynamicLink(Kernel32);
	
	int result = WinMain(Kernel32, 0, 0, 0);
	ExitProcess(0);
}


Here's my WinMain function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine , int nCmdShow) {
    WNDCLASSA windowClass = {};
    windowClass.style = CS_HREDRAW | CS_VREDRAW ;
    windowClass.lpfnWndProc = WndProc;
    windowClass.hInstance = hInstance;
    windowClass.lpszClassName = "NoLibrariesWindowClass";
    windowClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

    if (RegisterClassA(&windowClass))
    {
        HWND WindowHandle = CreateWindowExA(
            0, "NoLibrariesWindowClass", "Greetings",
            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
            0, 0, hInstance,	0
            );

        if (WindowHandle)
        {
            MSG Message;
            while (GetMessageA(&Message, NULL, 0, 0))
            {
                TranslateMessage(&Message);
                DispatchMessageA(&Message);
            }
        }
    }

    return 0;
}


By the way, the GetStockObject doesn't fail and returns the value 0x00900010.
Shouldn't hInstance be a handle of your module, and not of kernel32?

You can use GetModuleHandle(0) to obtain that.