News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

calling win32 APIs without imports!

Started by shakuni, October 16, 2007, 01:15:12 PM

Previous topic - Next topic

shakuni

I found this code while browsing through the examples that come with the masm32 package.

; =======================================
; NO_IMPORT by mob aka drcmda
; this program demonstrates how to write
; portable code... this code could be
; added to other executables with no prob.
; i'm over that virus shit so don't waste
; your time... i'm working on something
; like a executable patcher right now so
; portable code was very interesting for
; me...................................
; if you want to use other apis or other
; dll's then use this structure:
;
; 00      db ?? ;lenght of name
; 01 - ?? db ?? ;API name
; ??      dd ?? ;pointer
;
; then use 'GetApis' to find their
; pointers so you don't have to search
; the pointers with GetModuleHandle
; write to drcmda@gmx.de
; =======================================

; ---------------------------------------------------
; Build with MAKEIT.BAT to merge the .text and .data
; sections. Result is a 1024 byte length EXE file.
; ---------------------------------------------------

.486
.Model      Flat, Stdcall
Option      Casemap:None

.Data

; kernel32.dll api's
___Kernel32         db 14,"GetProcAddress"
_Getprocaddress     dd 0
                    db 11,"LoadLibrary"
_Loadlibrary        dd 0
                    db 11,"ExitProcess"
_Exitprocess        dd 0

; user32.dll api's
___User32           db 11,"MessageBeep"
_Messagebeep        dd 0
                    db 10,"MessageBox"
_MessageBox         dd 0                   

_Kernel             Dd 0
_User32             db "USER32",0
_Default            Dd 0   

.Code       
   
Start:
            Call    Delta
Delta:
            Pop     Ebp                                 ; get deltaofs   
            Sub     Ebp,Offset Delta                    ; for portability         
           
            Call    Get_Kernel                          ; get kernel base/set default
           
            Push    3                                   ; 3 api's in the kernel32 struc
            pop     Ecx
            Lea     Esi,[Ebp+Offset ___Kernel32]                                           
            Call    Get_Apis                            ; get kernel apis
                       
            Lea     Eax,[Ebp+Offset _User32]            ; load user32.dll
            Push    Eax
            Call    [Ebp+_Loadlibrary]           
           
            test    Eax,Eax
            jz      Error_Exit

            Mov     [Ebp+Offset _Default],Eax           ; store result in 'default'

            push    2                                   ; 4 api's in the user32 struc
            pop     Ecx
            Lea     Esi, [Ebp+Offset ___User32]                                           
            Call    Get_Apis                            ; get user32 apis           
                                 
            Push    -1
            Call    [Ebp+_Messagebeep]                  ; beep
           
            Push    0
            Call    _t02
            db      "little test",0
_t02:       Call    _t01
            db      "MessageBox without imports, funny eh?",0
_t01:       Push    0
            Call    [Ebp+_MessageBox]                   ; messagebox

Error_Exit:                               
            Push    0
            Call    [Ebp+_Exitprocess]                  ; get out


; ######################## get kernel ########################
; returns kernelbase and stores it in 'default' and 'kernel'
Get_Kernel:
            Mov     Ecx,[Esp+4] ; get kerneladdr from stack
           
Kernel_Loop:
            Xor     Edx,Edx
            Dec     Ecx
            Mov     Dx,[Ecx+3Ch]
            Test    Dx,0F800H
            Jnz     Kernel_Loop
            Cmp     Ecx,[Ecx+Edx+34H]
            Jnz     Kernel_Loop           
            Mov     [Ebp+Offset _Kernel],Ecx
            Mov     [Ebp+Offset _Default],Ecx                                             
            Ret

; ######################## get apis   ########################
; default   = dll base
; ecx       = number of api's in the structure
; esi       = pointer to structure
Get_Apis: 
            Xor     Ebx,Ebx
Api_Loop:
            Inc     Esi         ; scan through the api
            Push    Ecx         ; table and try to
            Movzx   ecx, byte ptr [Esi-1] ; addresses...               
            Push    Ecx
            Call    Get_Api
            Pop     Ebx
            Pop     Ecx
            Add     Esi,Ebx           
            Mov     [Esi],Eax
            Add     Esi,4
            Loop    Api_Loop
            Ret       

; ######################## get api    ########################
; default = dll base
; ecx     = structure entry
Get_Api:   
            Mov     Edx, [Ebp+Offset _Default]
            Add     Edx, [Edx+3Ch] ; get default module       
            Mov     Edx, [Edx+78H]
            Add     Edx, [Ebp+Offset _Default]

            Mov     Edi, [Edx+32] ;Get Addrofnames
            Add     Edi, [Ebp+Offset _Default]
            Mov     Edi, [Edi] ;Get Addrofnames
            Add     Edi, [Ebp+Offset _Default]
            Mov     Eax, [Edx+24] ;Get Numberofnames                                   
            Xor     Ebx,Ebx
Next_One:           
            Push    Ecx
            Inc     Ebx         
            Push    Esi
            Push    Edi
            Repz    Cmpsb ; compare api with export
            Pop     Edi
            Pop     Esi
            Jnz     Not_Found           
            Pop     Ecx
            Mov     Ecx, [Edx+36] ;Get Addrnameord
            Add     Ecx, [Ebp+Offset _Default]
            Dec     Ebx
            Movzx   eax, word ptr [Ecx+Ebx*2]                       
            Mov     Ebx, [Edx+28] ;Get Addroffunctions
            Add     Ebx, [Ebp+Offset _Default]
            Mov     Eax, [Ebx+Eax*4]               
            Add     Eax, [Ebp+Offset _Default]
            Ret
Not_Found: 
            Dec     Edi           
Loop_1:
            Inc     Edi
            Cmp     Byte Ptr [Edi],0
            Jnz     Loop_1

            Inc     Edi           
            Dec     Eax
            Jz      Exit_Search           
            Pop     Ecx
            Jmp     Next_One
Exit_Search: 
            Jmp     Error_Exit
            Ret                       
       
End         Start


The problem is that i have some problems understanding it.Although I know about the PE file structure and this program is just getting the handle for the api from the dll handling that api.But still there is some consusion.
can somebody please give some hint.

john9811

Hey i've the same problem too... i had some trouble finding where i could import additional dlls...

hutch--

mob wrote this piece of code some years ago and at the time it was a technique used to make an executable file harder to hack as you could not routinely set Softice to a breakpoint of a simple API like GetWindowText() and get it to stop when the API was being executed. Apart from an anti-hacking technique it is not much use apart from the virus brigade trying to stealth a section of code that calls various API functions by their address rather than by a name in the import table.

If we catch any of this nonsense in here it will get the hatchet like Haley's comet.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Vortex

I guess Windows 2000 will refuse silently to run the application because W2K expects at least one imported function from kernel32.dll

evlncrn8

correct, same with xp i think and most likely vista...

making an importless executable is rather uncommon, and used for spyware/malware/rootkits/code injection

@shakuni and john9811 - what exactly is it you're trying to achieve?

shakuni

QuoteI guess Windows 2000 will refuse silently to run the application because W2K expects at least one imported function from kernel32.dll
Quotesame with xp i think and most likely vista

I don't know about 2k but it works under XP and vista.

Quotewhat exactly is it you're trying to achieve?

Trying to learn "everything" about assembly language.
Trying to do what some people consider to be impossible.

MichaelW

Quote from: shakuni on October 18, 2007, 09:19:46 AM
Trying to learn "everything" about assembly language.
Trying to do what some people consider to be impossible.

The questionable part of this has nothing directly to do with assembly language.
eschew obfuscation

evlncrn8

Quote from: shakuni on October 18, 2007, 09:19:46 AM
Trying to do what some people consider to be impossible.

hows it impossible if someone has already shown its possible?

and hmm you're right it does work in xp.. just tested.. patch some exe with imports to have none (wipe data directories in pe header), and put an int 3 at the entrypoint.. it got there... odd

shakuni

QuoteThe questionable part of this has nothing directly to do with assembly language.

Yes Sir,it has nothing to do with "assembly language". But it is certainly related to application of assembly language.

Quotehows it impossible if someone has already shown its possible?

Yes Sir,it has been done already.But when I say that I am trying to do impossible things with assembly language, those are some other things that come to my mind while studying.The problems I ask, like the one above, is only a mean to that end.I would very soon post about those impossible things.

Vortex

QuoteBut when I say that I am trying to do impossible things with assembly language

If something is feasible, it means that it's not impossible to do :)

shakuni

yes you're right, but "some people" consider it impossible.

seeq

Yes, win2000 expects at least one imported function from kernel32.dll. But Microsoft removes this rule on XP and Vista, may be on win2000+sp4 this code will work.
I don't remember correctly. Only some Sp's require IAT
About this method.
This is old known method, by getting address of kernel32.dll from stack. Many commercial protectors and packers (like Asprotect and others) use this method.
For executing executables Windows uses CreateProcess function. In internals of this function has code:

7C816FB4 _BaseProcessStart@4:                   
7C816FB4                 push    0Ch
7C816FB6                 push    offset stru_7C816FE0
7C816FBB                 call    __SEH_prolog
7C816FC0                 and     dword ptr [ebp-4], 0
7C816FC4                 push    4
7C816FC6                 lea     eax, [ebp+8]
7C816FC9                 push    eax
7C816FCA                 push    9
7C816FCC                 push    0FFFFFFFEh
7C816FCE                 call    ds:__imp__NtSetInformationThread@16
7C816FD4                 call    dword ptr [ebp+8] ; this call executes code at EntryPoint of PE file;
7C816FD7                 push    eax             ; dwExitCode
7C816FD8
7C816FD8 loc_7C816FD8:                           
7C816FD8                 call    _ExitThread@4 
7C816FDD                 nop
7C816FDE                 nop


So in the stack we have 7C816FD7
So we have address from kernel32.dll, then we parsing it for getting exports, this is must be clear, if you know PE files stucrure.

p.s this method will no work with dll files because DllMain not executing with CreateProcess function.

shakuni

Quotethen we parsing it for getting exports

yes sir,I finally got it.Thank you very much.

One more question,how did you get the code for the createprocess function.Just give me the idea and I will do the remaining research.Thanks.

evlncrn8

is it just me who has a bad feeling of the direction of this code?

Vortex

QuoteThis is old known method, by getting address of kernel32.dll from stack.

This method,is it applicable on all the versions of Windows?