flat assembler
Message board for the users of flat assembler.

Index > Windows > Super simple fasm app?

Author
Thread Post new topic Reply to topic
birdus



Joined: 11 Oct 2009
Posts: 7
birdus
Can someone provide me with an ultra simple fasm app? No includes, no invokes. Just maybe declare a data value, put that into a register, then the exit code.

I just need a basic shell to get me started.

Thanks!!!
Jay
Post 12 Oct 2009, 00:20
View user's profile Send private message Reply with quote
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
Unfortunately, you need an invoke or the program will crash (particularly, a call to ExitProcess). However, if you don't mind crashing...

[code]format PE console ;console window[
mov eax, 54/code]

Though, you don't declare variables in assembly, technically. Essentually, unlike HLLs, assembly outputs EXACTLY what you give it. HLLs have a little wiggle room.
Post 12 Oct 2009, 01:31
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
Pinecone_



Joined: 28 Apr 2008
Posts: 180
Pinecone_
kohlrak wrote:
Unfortunately, you need an invoke or the program will crash (particularly, a call to ExitProcess). However, if you don't mind crashing...
Not sure if it's reliable across diferent windows versions, but a simple ret does the job on xp sp2. However since he wants a shell, maybe he wants to be able to call api functions, so maybe you should check the "PEDEMO" example that comes with the windows fasm package. I think it's what you're looking for.

Here it is so you don't have to look it up:
Code:
; Example of making 32-bit PE program as raw code and data

format PE GUI
entry start

section '.text' code readable executable

  start:

 push    0
   push    _caption
    push    _message
    push    0
   call    [MessageBoxA]

   push    0
   call    [ExitProcess]

section '.data' data readable writeable

  _caption db 'Win32 assembly program',0
  _message db 'Hello World!',0

section '.idata' import data readable writeable

  dd 0,0,0,RVA kernel_name,RVA kernel_table
  dd 0,0,0,RVA user_name,RVA user_table
  dd 0,0,0,0,0

  kernel_table:
    ExitProcess dd RVA _ExitProcess
    dd 0
  user_table:
    MessageBoxA dd RVA _MessageBoxA
    dd 0

  kernel_name db 'KERNEL32.DLL',0
  user_name db 'USER32.DLL',0

  _ExitProcess dw 0
    db 'ExitProcess',0
  _MessageBoxA dw 0
    db 'MessageBoxA',0

section '.reloc' fixups data readable discardable  ; needed for Win32s
    



Here's the equivalent with includes:
Code:
format PE GUI
entry start

include '%include%\win32a.inc'

section '.text' code readable executable
      
    start:
          invoke MessageBox, 0, _message, _caption, 0
         invoke ExitProcess, 0
               
section '.data' data readable writeable
       
    _caption db 'Win32 assembly program', 0
   _message db 'Hello World!', 0
     
section '.idata' import data readable writeable
       
    library kernel32,               'kernel32.dll',\
         user32,                 'user32.dll'
                      
    include '%include%\api\kernel32.inc'
    include '%include%\api\user32.inc'    



Or exactly what you asked for in your first post:
Code:
format PE GUI
entry start

section '.code' code readable executable
    
    start:
          mov eax, 1
  ret    
But as I said, I don't know how reliable ret is, and it wouldn't be much good as a shell because you can't call the API.
Post 12 Oct 2009, 01:49
View user's profile Send private message Reply with quote
birdus



Joined: 11 Oct 2009
Posts: 7
birdus
When you execute:

call [ExitProcess]

or:

invoke ExitProcess

isn't it just executing several lines of assembly language in a subroutine in another module? I guess one of the things I was curious about was what the precise few lines of assembly were that were required to exit vs. making the subroutine call.

Additionally, trying to get a feel for the sections required by fasm. Looks like they all start out with:

format PE GUI
entry start

section '.code' code readable executable

followed by instructions, followed by the data section. In a book I've got on Turbo Assembler, the data section comes before the code section, which makes more sense to me, but I'll get used to fasm's different order of sections.

Is there a document that can guide me through these most basic aspects of fasm (so as not to have you kind folks lead me by the hand)?

I appreciate the help!!!

Thanks,
Jay
Post 12 Oct 2009, 02:49
View user's profile Send private message Reply with quote
birdus



Joined: 11 Oct 2009
Posts: 7
birdus
As a quick followup, in the DOS examples I see in the book I'm looking at, each program ends with:

Exit:
mov ah, 04Ch
mov al, 0
int 21h

I was just assuming that a program written for fasm (even for Windows) would end with something similar. Is this way off base?

Thanks,
Jay
Post 12 Oct 2009, 02:53
View user's profile Send private message Reply with quote
birdus



Joined: 11 Oct 2009
Posts: 7
birdus
One more thing. Is there a simple example console app I can look at somewhere? Maybe something like hello, world? Again, right now, just going for ultra simple so I can get a grip on the basic layout of a fasm app. Then I'll have a framework to begin learning about registers, jumps, control structures, etc.

Thanks,
Jay
Post 12 Oct 2009, 02:57
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 16858
Location: In your JS exploiting you and your system
revolution
birdus: The order of sections is purely up to the programmers choice. You can put the data section first if you want to. You can have multiple data section with multiple code sections with an import section etc. all in one exe in whatever order you feel is suitable.

To make a console app just start with "format pe console". Then you can use the standard input and output functions to access the console.
Post 12 Oct 2009, 03:23
View user's profile Send private message Visit poster's website Reply with quote
birdus



Joined: 11 Oct 2009
Posts: 7
birdus
Thanks, revolution!

Jay
Post 12 Oct 2009, 04:18
View user's profile Send private message Reply with quote
sleepsleep



Joined: 05 Oct 2006
Posts: 8484
Location: ˛                             ⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣Posts: 334455
sleepsleep
i would suggest u try using the win32ax.inc
they speed up the job and well, save time and our brain damages.
Post 12 Oct 2009, 06:09
View user's profile Send private message Reply with quote
Uwar



Joined: 09 Oct 2009
Posts: 11
Uwar
The extremly simple APP (no includes, no invokes)
Code:
; NAKED WIN32APP in FASM
format PE GUI
entry main

struc WNDCLASSEX{
 .cbsize         dd  0x00000000
 .style          dd  0x00000000
 .lpfnwndproc    dd  0x00000000
 .cbclsextra     dd  0x00000000
 .cbwndextra     dd  0x00000000
 .hinstance      dd  0x00000000
 .hicon          dd  0x00000000
 .hcursor        dd  0x00000000
 .hbrbackground  dd  0x00000000
 .lpszmenuname   dd  0x00000000
 .lpszclassname  dd  0x00000000
 .hiconsm        dd  0x00000000
} 

struc POINT{
 .x  dd 0x00000000
 .y  dd 0x00000000
}

struc MSG{
 .hwnd     dd  0x00000000
 .message  dd  0x00000000
 .wparam   dd  0x00000000
 .lparam   dd  0x00000000
 .time     dd  0x00000000
 .pt       POINT
}

section '.code' code readable executable
;------------------------------------------------------------------------------
 wndproc:
    push  ebp
    mov   ebp,esp
    cmp   dword [ebp + 0x0C], 0x00000002
    jz    case_WM_DESTROY
    cmp   dword [ebp + 0x0C], 0x00000201
    jz    case_WM_LBUTTONDOWN
    push  case_DEFAULT
    retn

 case_WM_DESTROY:
    push  0x00000000
    call  [user32.PostQuitMessage]
    mov   eax, 0x00000000
    leave
    retn  0x0010

 case_WM_LBUTTONDOWN:
    push  0x00000000
    push  sz_wndcaption
    push  sz_message
    push  0x00000000
    call  [user32.MessageBoxA]
    mov   eax, 0x00000000
    leave
    retn  0x0010

 case_DEFAULT:
    mov   eax, [ebp + 0x08]
    mov   ebx, [ebp + 0x0C]
    mov   ecx, [ebp + 0x10]
    mov   edx, [ebp + 0x14]
    push  edx
    push  ecx
    push  ebx
    push  eax
    call  [user32.DefWindowProcA]
    leave
    retn  0x0010
;------------------------------------------------------------------------------
 winmain:
    push  ebp
    mov   ebp, esp
    mov   dword [wndclass.cbsize], 0x00000030
    mov   dword [wndclass.style], 0x00000003
    mov   dword [wndclass.lpfnwndproc], wndproc
    mov   dword [wndclass.cbclsextra], 0x00000000
    mov   dword [wndclass.cbwndextra], 0x00000000
    push  dword [hinstance]
    pop   dword [wndclass.hinstance]
    push  0x00007F00
    push  0x00000000
    call  [user32.LoadIconA]
    mov   [wndclass.hicon], eax
    mov   [wndclass.hiconsm], eax
    push  0x00007F00
    push  0x00000000
    call  [user32.LoadCursorA]
    mov   [wndclass.hcursor], eax
    mov   dword [wndclass.hbrbackground], 0x00000006
    mov   dword [wndclass.lpszmenuname], 0x00000000
    mov   dword [wndclass.lpszclassname], sz_wndcls
    push  wndclass
    call  [user32.RegisterClassExA]
    push  0x00000000
    push  dword [ebp + 0x08]
    push  0x00000000
    push  0x00000000
    push  0x00000258
    push  0x00000320
    push  0x00000000
    push  0x00000000
    push  0x00CF0000
    push  sz_wndcaption
    push  sz_wndcls
    push  0x00000000
    call  [user32.CreateWindowExA]
    mov   [hwnd], eax
    push  0x00000001
    push  dword [hwnd]
    call  [user32.ShowWindow]
    push  dword[hwnd]
    call  [user32.UpdateWindow]
 messagepump:
    push  0x00000000
    push  0x00000000
    push  0x00000000
    push  msg
    call  [user32.GetMessageA]
    cmp   eax, 0x00000000
    jz    winmainend
    push  msg
    call  [user32.TranslateMessage]
    push  msg
    call  [user32.DispatchMessageA]
    push  messagepump
    retn
 winmainend:
    mov eax,[msg.wparam]
    leave
    retn  0010h
;------------------------------------------------------------------------------
 main:
    push  0x00000000
    call  [kernel32.GetModuleHandleA]
    mov   [hinstance], eax
    call  [kernel32.GetCommandLineA]
    mov   [cmdline], eax
    push  0x000000A
    push  dword [cmdline]
    push  0x00000000
    push  dword [hinstance]
    call  winmain
    push  0x00000000
    call  [kernel32.ExitProcess]
;------------------------------------------------------------------------------
section '.data' data readable writeable
;------------------------------------------------------------------------------
 hinstance:
    dd  0x00000000
 cmdline:
    dd  0x00000000
 hwnd:
    dd  0x00000000
;------------------------------------------------------------------------------
 wndclass WNDCLASSEX
 msg      MSG
;------------------------------------------------------------------------------
 sz_wndcls:
    db  'wndcls', 0
 sz_wndcaption:
    db  '<caption>',0
 sz_message:
    db  'Received click "message".',0
;------------------------------------------------------------------------------
section '.eimport' import data readable writable
;------------------------------------------------------------------------------
 dd 0,0,0, RVA kernel_name, RVA kernel_table
 dd 0,0,0, RVA user_name,   RVA user_table
 dd 0,0,0,0,0 ; end

 kernel_table:
    kernel32.ExitProcess      dd RVA ExitProcess
    kernel32.GetCommandLineA  dd RVA GetCommandLineA
    kernel32.GetModuleHandleA dd RVA GetModuleHandleA
    dd 0x00000000 ; end

 user_table:
    user32.MessageBoxA      dd RVA MessageBoxA
    user32.LoadIconA        dd RVA LoadIconA
    user32.LoadCursorA      dd RVA LoadCursorA
    user32.DefWindowProcA   dd RVA DefWindowProcA
    user32.RegisterClassExA dd RVA RegisterClassExA
    user32.CreateWindowExA  dd RVA CreateWindowExA
    user32.PostQuitMessage  dd RVA PostQuitMessage
    user32.ShowWindow       dd RVA ShowWindow
    user32.UpdateWindow     dd RVA UpdateWindow
    user32.GetMessageA      dd RVA GetMessageA
    user32.TranslateMessage dd RVA TranslateMessage
    user32.DispatchMessageA dd RVA DispatchMessageA
    dd 0x00000000 ; end

 kernel_name db 'KERNEL32.DLL', 0
 user_name   db 'USER32.DLL',   0

; kernel32 imports
 ExitProcess      dw       0
    db 'ExitProcess',      0
 GetCommandLineA  dw       0
    db 'GetCommandLineA',  0
 GetModuleHandleA dw       0
    db 'GetModuleHandleA', 0

; user32 imports
 MessageBoxA      dw       0
    db 'MessageBoxA',      0
 LoadIconA        dw       0
    db 'LoadIconA',        0
 LoadCursorA      dw       0
    db 'LoadCursorA',      0
 DefWindowProcA   dw       0
    db 'DefWindowProcA',   0
 RegisterClassExA dw       0
    db 'RegisterClassExA', 0
 CreateWindowExA  dw       0
    db 'CreateWindowExA',  0
 PostQuitMessage  dw       0
    db 'PostQuitMessage',  0
 ShowWindow       dw       0
    db 'ShowWindow',       0
 UpdateWindow     dw       0
    db 'UpdateWindow',     0
 GetMessageA      dw       0
    db 'GetMessageA',      0
 TranslateMessage dw       0
    db 'TranslateMessage', 0
 DispatchMessageA dw       0
    db 'DispatchMessageA', 0
;------------------------------------------------------------------------------

    
Post 12 Oct 2009, 21:55
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Uwar, an small contribution:
Code:
;------------------------------------------------------------------------------
 wndproc:
    cmp   dword [esp + 0x08], 0x00000002
    je    case_WM_DESTROY

    cmp   dword [esp + 0x08], 0x00000201
    je    case_WM_LBUTTONDOWN

    jmp   [user32.DefWindowProcA] ; WARNING: THIS IS POSSIBLE ONLY BECAUSE THIS FUNCTION HAS THE SAME PROTOTYPE WNDPROC HAS

 case_WM_DESTROY:
    push  0x00000000
    call  [user32.PostQuitMessage]

    xor   eax, eax
    retn  0x0010

 case_WM_LBUTTONDOWN:
    push  0x00000000
    push  sz_wndcaption
    push  sz_message
    push  0x00000000
    call  [user32.MessageBoxA]

    xor   eax, eax
    retn  0x0010
;------------------------------------------------------------------------------    


Unless you have an specific purpose for those PUSH label/RETN, you better use JMP label instead, it is much more efficient (not only for the extra instruction and memory read and write, but also because you sabotage the return buffer because of that unpaired RETN with a CALL)
Post 12 Oct 2009, 22:18
View user's profile Send private message Reply with quote
birdus



Joined: 11 Oct 2009
Posts: 7
birdus
Wow!!! So that's like the most basic C app back in the early days of Windows development! I.e., before wrapping all the details in a class library.

Of course it's not nearly the simplest asm app you can build for fasm, but it's still very interesting! I guess it IS the simplest WINDOWS app (i.e., app with a window, or, non-console app) you can build (without using libraries). Quite educational for me!

Thanks!!!
Jay
Post 13 Oct 2009, 01:22
View user's profile Send private message Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 759
Location: Massachusetts, USA
bitshifter
Hi birdus, welcome to FASM forum, its nice to see new members Smile

Learning ASM and Win32 are two totally different things...
You will pull your hair out trying to learn them both at same time.
Learning Win32 is best viewed in its native language, C.
http://winprog.org/tutorial/
After, you can easily identify with ASM.
http://win32assembly.online.fr/tutorials.html
Also there are nice examples in FASM/EXAMPLES folder.
Post 13 Oct 2009, 03:57
View user's profile Send private message Reply with quote
birdus



Joined: 11 Oct 2009
Posts: 7
birdus
Thanks for the welcome, bitshifter.

Right now, I am definitely interested ONLY in learning assembly language!

I did find the Windows example fun and interesting, though!

Thanks for the links.

Jay
Post 13 Oct 2009, 05:08
View user's profile Send private message Reply with quote
Uwar



Joined: 09 Oct 2009
Posts: 11
Uwar
Of course it is a super simple GUI Windows App.
Previous listing with the local variables and improvements suggested by LocoDelAssembly:
Code:
format PE GUI
entry main

; windows constants
CS_HREDRAW          = 0x00000002
CS_VREDRAW          = 0x00000001

IDC_ARROW           = 0x00007F00
IDI_APPLICATION     = 0x00007F00

WS_OVERLAPPEDWINDOW = 0x00CF0000

SW_SHOWDEFAULT      = 0x0000000A

WM_CREATE           = 0x00000001
WM_DESTROY          = 0x00000002

MB_ICONERROR        = 0x00000010

section '.code' code readable executable
;------------------------------------------------------------------------------
 showerror:
    push  EBP
    mov   EBP, ESP
    
    ; CHAR   [0x10] l_buff
    ; STRING        l_sz_buff = &l_buff
    sub  ESP, 0x14
    .l_sz_buff  equ EBP - 0x14
    .l_buff     equ EBP - 0x10
    
    lea   EAX,  [.l_buff]
    mov   dword [.l_sz_buff], EAX

    call [kernel32.getLastError]
    
    push  EAX
    push  .sz_fmt
    push  dword [.l_sz_buff]
    call  [user32.wsprintf]
    add   ESP, 0x0C ; cleans up the stack after CDECL user32.wsprintf
    
    push  MB_ICONERROR
    push  .sz_caption
    push  dword [.l_sz_buff]
    push  0x00000000
    call  [user32.messageBox]

    leave
    retn

 .sz_fmt     db '0x%08X', 0x00 ; static const
 .sz_caption db 'Msg',    0x00 ; static const 
;------------------------------------------------------------------------------
 wndproc:  ; (o_hwnd : HANDLE, o_hmsg : HANDLE, o_wparam : DWORD, o_lparam : DWORD) : DWORD
    push  EBP
    mov   EBP, ESP
    .o_hwnd   equ EBP + 0x08
    .o_hmsg   equ EBP + 0x0C
    .o_wparam equ EBP + 0x10
    .o_lparam equ EBP + 0x14
    
    cmp   dword [.o_hmsg], WM_DESTROY
    je    .case_WM_DESTROY

    leave
    jmp   [user32.defWindowProc]

 .end:
    leave
    retn  0x10

 .case_WM_DESTROY:
    push  dword 0x00000000                
    call  [user32.postQuitMessage]
    xor   EAX, EAX
    jmp   .end
;------------------------------------------------------------------------------
 winmain:  ; (o_hinstance : HANDLE, o_hprevinstance : HANDLE, o_sz_cmdline : STRING , o_cmdshow : DWORD) : DWORD
    push  EBP
    mov   EBP, ESP
    .o_hinstance                equ EBP + 0x08
    .o_hprevinstance            equ EBP + 0x0C ; obsolete
    .o_sz_cmdline               equ EBP + 0x10
    .o_cmdshow                  equ EBP + 0x14
    
    ; WNDCLASSEX l_wndclassex
    ; HANDLE     l_hwndclassex = &l_wndclassex
    ; MSG        l_msg  
    ; HANDLE     l_hmsg        = &l_msg
    ; HANDLE     l_hwnd
    sub   ESP, 0x58
    .l_hwnd                     equ EBP - 0x58  ;        HANDLE     sizeof 0x04
    .l_hmsg                     equ EBP - 0x54  ;        HANDLE     sizeof 0x04
    .l_msg.hwnd                 equ EBP - 0x50  ; struct MSG        sizeof 0x1C
    .l_msg.message              equ EBP - 0x4C
    .l_msg.wparam               equ EBP - 0x48
    .l_msg.lparam               equ EBP - 0x44
    .l_msg.time                 equ EBP - 0x40
    .l_msg.pt.x                 equ EBP - 0x3C
    .l_msg.pt.y                 equ EBP - 0x38
    .l_hwndclassex              equ EBP - 0x34  ;        HANDLE     sizeof 0x04
    .l_wndclassex.size          equ EBP - 0x30  ; struct WNDCLASSEX sizeof 0x30
    .l_wndclassex.style         equ EBP - 0x2C
    .l_wndclassex.wndproc       equ EBP - 0x28
    .l_wndclassex.clsextrabytes equ EBP - 0x24
    .l_wndclassex.wndextrabytes equ EBP - 0x20
    .l_wndclassex.hinstance     equ EBP - 0x1C
    .l_wndclassex.hicon         equ EBP - 0x18
    .l_wndclassex.hcursor       equ EBP - 0x14
    .l_wndclassex.hbrbackground equ EBP - 0x10
    .l_wndclassex.menuname      equ EBP - 0x0C
    .l_wndclassex.classname     equ EBP - 0x08
    .l_wndclassex.hiconsm       equ EBP - 0x04

    lea   EAX, [EBP - 0x30]
    mov   dword [.l_hwndclassex], EAX
  
    lea   EAX, [EBP - 0x50]
    mov   dword [.l_hmsg       ], EAX
        
    ; l_wndclassex.size = 0x00000030
    mov   dword [.l_wndclassex.size], 0x00000030
    ; l_wndclassex.style = CS_VREDRAW | CS_HREDRAW
    mov   dword [.l_wndclassex.style], CS_HREDRAW or CS_VREDRAW;
    ; l_wndclassex.wndproc = &defwndproc
    mov   dword [.l_wndclassex.wndproc], wndproc
    ; l_wndclassex.clsextrabytes = 0x00000000
    mov   dword [.l_wndclassex.clsextrabytes], 0x00000000
    ; wndclassex.wndextrabytes = 0x00000000
    mov   dword [.l_wndclassex.wndextrabytes], 0x00000000
    ; l_wndclass.hinstance = o_hinstance
    push  dword [.o_hinstance]
    pop   dword [.l_wndclassex.hinstance]
    ; l_wndclassex.hicon = wndclassex.hiconsm = user32.loadIcon(0x00000000, 0x00007F00)
    push  dword IDI_APPLICATION
    push  dword 0x00000000
    call  [user32.loadIcon]
    mov   dword [.l_wndclassex.hicon  ], EAX
    mov   dword [.l_wndclassex.hiconsm], EAX
    ; l_wndclassex.hcursor = user32.loadCursor(0x00000000, 0x00007F00) 
    push  dword IDC_ARROW
    push  dword 0x00000000
    call  [user32.loadCursor]
    mov   dword [.l_wndclassex.hcursor], EAX
    ; l_wndclassex.hbrbackground = gdi32.getStockObject(0x00000000)
    push  dword 0x00000000
    call  [gdi32.getStockObject]
    mov   dword [.l_wndclassex.hbrbackground], EAX
    ; l_wndclassex.menuname = 0x00000000
    mov   dword [.l_wndclassex.menuname], 0x00000000
    ; l_wndclassex.classname = .sz_clsname
    mov   dword [.l_wndclassex.classname], .sz_clsname

    ; registerClassEx(l_wndclassex)
    push  dword [.l_hwndclassex]
    call  [user32.registerClassEx]
    cmp   EAX, 0x00000000
    je    .error
    
    ; l_hwnd = createWindowEx(
    ;            0x00000000,
    ;            l_wndclassex.classname,
    ;            &sz_wndcaption,
    ;            WS_OVERLAPPEDWINDOW,
    ;            0x00000000,
    ;            0x00000000,
    ;            0x00000320,
    ;            0x00000258,
    ;            0x00000000,
    ;            0x00000000,
    ;            o_hinstance,
    ;            0x00000000,
    ;          )
    push  dword 0x00000000
    push  dword [.o_hinstance]
    push  dword 0x00000000
    push  dword 0x00000000
    push  dword 0x00000258
    push  dword 0x00000320
    push  dword 0x00000000
    push  dword 0x00000000
    push  dword WS_OVERLAPPEDWINDOW
    push  .sz_wndcaption
    push  dword [.l_wndclassex.classname]
    push  dword 0x00000000
    call  [user32.createWindowEx]
    cmp   EAX, 0x00000000
    je    .error
    mov   [.l_hwnd], EAX
    
    ; user32.showWindow(l_hwnd, o_cmdshow)
    push  dword [.o_cmdshow]
    push  dword [.l_hwnd   ]
    call  [user32.showWindow]

    ; user32.updateWindow(l_hwnd)
    push  dword [.l_hwnd]
    call  [user32.updateWindow]
    cmp   EAX, 0x00000000
    je    .error

 .msgpump:
    ; if(user32.getMessage(l_msg, 0x00, 0x00, 0x00) == 0x00) jump .end
    push  dword 0x00000000
    push  dword 0x00000000
    push  dword 0x00000000
    push  dword [.l_hmsg]
    call  [user32.getMessage]
    cmp   EAX,  0x00000000
    je   .end

    ; user32.translateMessage(l_msg)
    push  dword [.l_hmsg]
    call  [user32.translateMessage]

    ; user32.DispatchMessageA(&msg)
    push  dword [.l_hmsg]
    call  [user32.dispatchMessage]

    ; jump msgpump
    jmp  .msgpump

 .end:
    mov   EAX, [.l_msg.wparam]
    leave
    retn  0x10

 .error:
    call showerror
    jmp  .end

 .sz_clsname    db 'clsname',    0x00 ; static const
 .sz_wndcaption db 'windowdemo', 0x00 ; static const
;------------------------------------------------------------------------------
 main:  ; () : VOID
    push  ebp    
    mov   ebp, esp  

    ; winmain(
    ;   kernel32.getModuleHandle(0x00000000),
    ;   0x00000000,
    ;   kernel32.getCommandLineA(),
    ;   SW_SHOWDEFAULT
    ; )
    push  dword SW_SHOWDEFAULT

    call  [kernel32.getCommandLine]
    cmp   EAX, dword 0x00000000
    je    .error
    push  EAX

    push  dword 0x00000000

    push  dword 0x00000000
    call  [kernel32.getModuleHandle]
    cmp   EAX, dword 0x00000000
    je    .error
    push  EAX  

    call  winmain

.end:
    ; return 0
    push  dword 0x00000000 
    call  [kernel32.exitProcess]
    leave

.error:
    call showerror
    jmp  .end
;------------------------------------------------------------------------------
section '.data' data readable writeable
;------------------------------------------------------------------------------
db 0x00 ; to prevent empty data section in PE
;------------------------------------------------------------------------------
section '.eimport' import data readable writable
;------------------------------------------------------------------------------
 dd 0,0,0, RVA sz_kernel32!dll, RVA kernel32
 dd 0,0,0, RVA sz_user32!dll,   RVA user32
 dd 0,0,0, RVA sz_gdi32!dll,    RVA gdi32
 dd 0,0,0, 0,                   0 ; end

 kernel32:
    .exitProcess      dd RVA kernel32!dll.ExitProcess
    .getCommandLine   dd RVA kernel32!dll.GetCommandLineA
    .getModuleHandle  dd RVA kernel32!dll.GetModuleHandleA
    .getLastError     dd RVA kernel32!dll.GetLastError
                      dd 0x00000000 ; end

 user32:
    .messageBox       dd RVA user32!dll.MessageBoxA
    .loadIcon         dd RVA user32!dll.LoadIconA
    .loadCursor       dd RVA user32!dll.LoadCursorA
    .defWindowProc    dd RVA user32!dll.DefWindowProcA
    .registerClassEx  dd RVA user32!dll.RegisterClassExA
    .createWindowEx   dd RVA user32!dll.CreateWindowExA
    .postQuitMessage  dd RVA user32!dll.PostQuitMessage
    .showWindow       dd RVA user32!dll.ShowWindow
    .updateWindow     dd RVA user32!dll.UpdateWindow
    .getMessage       dd RVA user32!dll.GetMessageA
    .translateMessage dd RVA user32!dll.TranslateMessage
    .dispatchMessage  dd RVA user32!dll.DispatchMessageA
    .wsprintf         dd RVA user32!dll.wsprintfA
                      dd 0x00000000 ; end

 gdi32:
    .getStockObject    dd RVA gdi32!dll.GetStockObject
                       dd 0x00000000 ; end

 sz_kernel32!dll db 'KERNEL32.DLL', 0
 sz_user32!dll   db 'USER32.DLL',   0
 sz_gdi32!dll    db 'GDI32.DLL',    0

 ; kernel32 imports
 kernel32!dll:
    .ExitProcess      dw      0
      db 'ExitProcess',       0
    .GetCommandLineA  dw      0  
      db 'GetCommandLineA',   0 
    .GetModuleHandleA dw      0
      db 'GetModuleHandleA',  0
    .GetLastError     dw      0
      db 'GetLastError',      0

 ; user32 imports
 user32!dll:
    .MessageBoxA      dw      0
      db 'MessageBoxA',       0
    .LoadIconA        dw      0
      db 'LoadIconA',         0
    .LoadCursorA      dw      0
      db 'LoadCursorA',       0
    .DefWindowProcA   dw      0
      db 'DefWindowProcA',    0
    .RegisterClassExA dw      0
      db 'RegisterClassExA',  0
    .CreateWindowExA  dw      0
      db 'CreateWindowExA',   0
    .PostQuitMessage  dw      0
      db 'PostQuitMessage',   0
    .ShowWindow       dw      0
      db 'ShowWindow',        0
    .UpdateWindow     dw      0
      db 'UpdateWindow',      0
    .GetMessageA      dw      0
      db 'GetMessageA',       0
    .TranslateMessage dw      0
      db 'TranslateMessage',  0
    .DispatchMessageA dw      0
      db 'DispatchMessageA',  0
    .wsprintfA        dw      0
      db 'wsprintfA',         0

 ; gdi32 imports
 gdi32!dll:
    .GetStockObject   dw     0
      db 'GetStockObject',   0
;------------------------------------------------------------------------------    
Post 13 Oct 2009, 14:03
View user's profile Send private message Reply with quote
Alphonso



Joined: 16 Jan 2007
Posts: 294
Alphonso
Hi birdus and welcome to asm. I think it's the invokes and includes that are what actually make it ultra simple. I'm not a professional programmer and don't know C but having tried some of the other assemblers have found FASM is very intuitive and easy to learn, at least for the basic stuff I use it for. Very Happy

Pinecone_ wrote:

Or exactly what you asked for in your first post:
Code:
format PE GUI
entry start

section '.code' code readable executable
     
    start:
          mov eax, 1
  ret    
But as I said, I don't know how reliable ret is, and it wouldn't be much good as a shell because you can't call the API.
If we're going to use an ugly 'ret' IIRC it wont work in w2k which AFAIK requires your app' to load kernel32.dll.


Still, if it works then we could add the API's as required. Here's a rough snippet with no includes, invokes or imports even to display a 'Goodbye' Messagebox.
Code:
format PE GUI 4.0
entry start

section '.code' code readable executable

  start:
         mov    esi,[esp]
         and    esi,0ffff0000h                                  ;Alignment is searches best friend Wink
@@:
         mov    ax,[esi]
         cmp    ax,'MZ'
         je     PossibleStart                                   ;Look for start of Kernel32.dll
         sub    esi,10000h                                      ;64k byte alignment
         jnz    @b
         ret                                                    ;Failed?, probably crash before this Wink

PossibleStart :
         mov    ebx,[esi+3ch]                                   ;offset to PE [MZ + 3Ch]
         cmp    dword [esi+ebx],'PE'                            ;If MZ start then PE header should be here
         jne    @b                                              ;Fluke MZ, try again

         mov    eax,[esi+ebx+78h]                               ;Export Table

         mov    ecx,[esi+eax+4*6]                               ;No. of Names
         mov    edi,[esi+eax+4*7]                               ;Address Table
         mov    ebx,[esi+eax+4*8]                               ;Name Pointer Table
         mov    ebp,[esi+eax+4*9]                               ;Ordinal Table
         mov    edx,ebx                                         ;EDX = Name Pointer Table
@@:
         mov    eax,[esi+ebx]                                   ;Get Name Pointer and search
         cmp    dword[esi+eax],'GetP'                           ;for GetProcessAddress in Name Pointer Table
         je     Found_GetP
         add    ebx,4
         loop   @b                                              ;Just in case cant find it
         ret                                                    ;give up

Found_GetP:
         cmp    dword[esi+eax+4],'rocA'
         je     Found_rocA
         add    ebx,4
         jmp    @b
Found_rocA:
         cmp    dword[esi+eax+8],'ddre'
         je     Found_ddre
         add    ebx,4
         jmp    @b
Found_ddre:                                                     ;good enough or should we check for 'ss,0'?

         sub    ebx,edx                                         ;Name Pointer Table offset to GetProcessAddress
         shr    ebx,1                                           ;Ordinals are 'words', adjust for Ordinals
         add    ebp,esi
         movzx  ebx,word[ebp+ebx]                               ;Ordinal Table offset

         shl    ebx,2                                           ;back to dword steps

         add    ebx,edi                                         ;position in Address Table worked out from Ordinal Table
         mov    edi,[esi+ebx]                                   ;RVA
         add    edi,esi                                         ;edi = GetProcAddress function

         push   LoadLibrary
         push   esi
         call   edi                                             ;GetProcAddress,kernel32.dll,LoadLibraryA


         push   u32
         call   eax                                             ;LoadLibrary,user32.dll

         push   MessageBox
         push   eax
         call   edi                                             ;GetProcAddress,user32.dll,MessageBoxA

         push   0
         push   Caption
         push   Message
         push   0
         call   eax                                             ;MessageBox,0,Message,Caption,0

         ret                                                    ;lookup ExitProcess if you want it :p

         MessageBox     db 'MessageBoxA',0
         LoadLibrary    db 'LoadLibraryA',0
         u32            db 'user32.dll',0

         Caption        db 'Hello',0
         Message        db 'Goodbye',0
    
I don't think it's really useful for anything other than as an example and looking nice and clean under windows 'Dependency Walker'. It might upset some anti-virus software too as being suspicious. Razz
Post 13 Oct 2009, 15:41
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2019, Tomasz Grysztar.

Powered by rwasa.