Hello World Anyone?

Posts 1–12 of 12 · Page 1 of 1
Hello World Anyone?
Hello World in Assembly

As is customary with almost every language the first thing people learn to do is how to print out a string of text (Usually being "Hello World!"). In higher level languages this is usually fairly easy to accomplish in relatively few lines of code. For instance in C++ one could write:
Code:
#include <iostream>
using namespace std;

int main()
{
	cout << "Hello World!" << endl;
	return 0;
}
When it comes to assembly though, depending on the environment, a little more work is involved. If you were to disassemble the exe file generated by the above code you would see TONS of assembly code just to do this one simply task.

Back in the 'old days' when MS-DOS reigned supreme and any assembly programming was done is 16 bit you had direct access to the 'MS-DOS API' which allowed you to easily deal with any of the hardware in a fairly direct matter.
On the flip side you had to worry about the structure of your program in memory, which memory model to use etc etc.

For instance a 16 Bit version of Hello World in Assembly would look like this:
Code:
  .MODEL Small
  .STACK 100h
  .DATA
   msg db 'Hello World!',13,10,'$'
  .CODE
  start:
  mov ax, seg msg
  mov ds,ax
  mov ah, 09h
  lea dx, msg
  int 21h
  mov ax,4C00h
  int 21h
  end start
It's definitely a little more cryptic. First the memory model gets set, a stack size gets defined. Then the data block sets the variables we will be using. Strings used this way need to be ended with the '$' symbol. The 13 and 10 values are \R and \N respectively which is a newline basically the same as the ENDL command in the C++ sample.
The 'start:' label defines the start of the program. The next two lines make sure that the DataSegment actually points to the correct spot in memory.

The core of the above is the Int 21h call. It basically takes a parameter in the AH register and does something with it. You can see it gets called twice. Once with 09h in AH and another with AX having the of 4C00h (thus AH = 4C). Basically when we use INT 21h with AH=09H we are telling it to print a string to the command line whose address pointer sits in the DX Register. As you can see this is basically the 'COUT' statement in the C++ Source

The Second Int21 call basically says 'End of program and return what's in AL' which in this case is 0 so this is similar to the 'Return 0' statement in the C++ program.

Ok this is all great, but in a sense this is all irrelevant for writing assembly now-adays against the Windows API. Everything Windows does is using the 'flat' memory model which means theoretically you have access to a full 4gb of ram, while under DOS it would only give you 16kb, hence the need for segments. Also Windows provides functionality for a lot of the functionality you used to have to talk directly for the hardware for. SO in a sense programming Assembly for windows makes it a little more 'high-level' than old-school MS-DOS Programming.

So what if we now want to write a 32-bit Command-Line Version of 'Hello World' for Windows?
The trick here is to not reinvent the wheel or go to 'low level' as your first instict may be, but to work against the provided Windows API with methods in the Windows DLLs. This code is for Masm32 (different assemblers may need slight tweaks etc)

Code:
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib

.data
HelloWorld db "Hello World!", 0

.code
start:
invoke StdOut, addr HelloWorld
invoke ExitProcess, 0
end start
Looking at this code from the top you'll see again some initialization (target platform is a 386, using the 'flat' memory model , standard calling convention and we're case-sensitive in our names). Then you see a bunch of 'include' and 'includelib' statements. If you're familiar with C++ this is very similar to including a Header File and telling the linker that when when building it should also include a specific LIB file. So in this instance we're including the Windows,Kernel32 and masm32 files. This will allow us to make windows sytem calls.

Then we have the Data Segment again where we define our string (notice how this one is '0' terminated) after which we find the Code Segment. Instead of calling Interrupts as we did in the 16-bit sample we are now simply invoking existing Windows API Methods, namely: StdOut and Exit Process.
As you can probably guess StdOut takes as a parameter the pointer to the 'Hello World' String and Exit Process will return '0' since that's what we're passing int.
Notice that this is meant to be ran from within the command line otherwise it will just flash a window without altering the code to wait for input


Ok, Great! But now what if we want to show an actual Dialog inside of windows? Well the only change we'd have to do is basically change where we call StdOut to something that shows a window. Windows provides a function called MessageBox which is just what we're looking for. This function though is provided in the user32.dll so we'll need to make sure to include this in our code.

Looking at MSDN.microsoft.com we can find that the MessageBox functions takes the following parameters
Code:
int MessageBox(      
    HWND hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT uType
);
Where hWnd is the window Owner - Not needed so set to NULL
lpText is the pointer to the string to display: addr HelloWorld
lpCaption is the Caption for the window, which we just set to the same text for convenience
and uType is a enum which defines what buttons to show on the dialog, In this case just the 'OK' button.

The finished code for this would then look like this:


Code:
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
.data
HelloWorld db "Hello World!", 0
.code
start:
invoke MessageBox, NULL, addr HelloWorld, addr HelloWorld, MB_OK
invoke ExitProcess, 0
end start

Of course once this gets compiled when looking at it through a disassembler you will not see the code as nice as this, but that's for another time

(ok hint : you'd see something more like this but without the nice readable variable names)
Code:
...
push MB_OK
push offset HelloWorld
push offset HelloWorld
push NULL
call MessageBoxA
...
Holy crap! You wrote out the whole thing! Thanks a lot BA. Excellent explanation! May you live out the rest of your days in happiness!
Ok taking this one step further :
Now what if we wanted to make our own windows app with some controls on it? This means we need to do a few steps. First We need to create both WinMain and WndProc functions. WinMain is similar to your basic 'main' function in any old C++ program, and WndProc is processes all the messages that the window receives.

Luckily in Masm32 you can make what are basically function prototypes and treat them like functions in C++ (though if you're using winasm it sorta looks like VB code down do the horizontal line across the screen.... yuck!). Also with the amount of processing you need to do Masm has some handy macros such as if else while break etc etc.

Then to create the actual controls we use the CreateWindowEx Functions so it's really straightforward.
Most of the code maps pretty true to how a C++ app would be written so I don't think I'll spend much time going through it line by line - besides.. i'm sure no one will even read this...

Except of course for Why - which btw, See how even in Masm32 you can do higher level constructs of loops etc? Ditch the HLA man and just go this route



Code:
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

WinMain proto :DWORD, :DWORD, :DWORD, :DWORD

.data
ClassName db "WinClass", 0
AppName db "Window Hello", 0
TextBox db "edit",0
Button db "button",0
ButtonText db "Let's Do it!",0
DisplayText db "Hello World of Windows!",0
ButtonID WORD 1000h
EditID WORD 1001h

.data?
hInstance HINSTANCE ?
hEdit HWND ?
hButton HWND ?

.code
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke WinMain, hInstance, NULL, NULL, 0
invoke ExitProcess, eax

WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD
local wc:WNDCLASSEX
local msg:MSG
local hwnd:HWND

mov wc.cbSize, SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, offset WndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground, COLOR_BACKGROUND
mov wc.lpszMenuName, NULL
mov wc.lpszClassName, offset ClassName
invoke LoadIcon, NULL, IDI_APPLICATION
mov wc.hIcon, eax
mov wc.hIconSm, eax
invoke LoadCursor, NULL, IDC_ARROW
mov wc.hCursor, eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx, 0, addr ClassName, addr AppName, WS_OVERLAPPEDWINDOW or WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 300, 120, NULL,
NULL, hInst, NULL
mov hwnd, eax
.while TRUE
	invoke GetMessage, addr msg, NULL, 0, 0
	.break .if (!eax)
	invoke TranslateMessage, addr msg
	invoke DispatchMessage, addr msg
.endw
mov eax, msg.wParam
ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.if uMsg == WM_DESTROY
	invoke PostQuitMessage, 0
.elseif uMsg == WM_CREATE
	invoke CreateWindowEx,NULL,addr Button,addr ButtonText,WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON, 70,35,80,30,hWnd,ButtonID,hInstance,NULL
	mov hButton, eax
	invoke CreateWindowEx,WS_EX_CLIENTEDGE,addr TextBox, NULL, WS_CHILD or WS_VISIBLE,10,10,200,20,hWnd,EditID,hInstance,NULL
	mov hEdit, eax
.elseif uMsg == WM_COMMAND
	mov eax,wParam
	.if ax == ButtonID
		shr eax,10h
		.if ax == BN_CLICKED
			invoke SetWindowText,hEdit,addr DisplayText
		.endif
	.endif
.else
	invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
.endif
xor eax, eax
ret
WndProc endp

end start
Maybe for fun i'll rewrite this code to NOT use any macros like if/endif, invoke etc..

Must say though that using the windows API like this sure takes away part of the 'mystery' of assembly programming when you were coding directly against the hardware with INTs etc..
Quote Originally Posted by B1ackAnge1 View Post
Except of course for Why - which btw, See how even in Masm32 you can do higher level constructs of loops etc? Ditch the HLA man and just go this route
Hmmmm... maybe your right. It's just that the guy wrote a 900 page book called the "Art of Assembly Language" that I'm using to learn by, but if it's teaching me the wrong stuff, maybe I should give it up. I think I'll look at some reviews before I make my final decision....

And your right it does sort of make it look less cryptic... too less cryptic. I need to learn pure asm if I'm going to be able to reverse anything at all. So far theres just too much HLL stuff. But I have to say, that last code looked worse then HLA o_O?!
Well stick with whatever works for you. I've found a good combo for ME in MASM32/WinAsm. Also have VStudio setup to build asm files but doesn't play as nice

The thing with learning is write something like this, then run it through something like ollydbg and see what it turned it into. Since they're relatively small programs they should be easy to follow and it will show you what's going on behind the scenes so you can recognize things when you seem them 'in the field' so to speak. I rewrote your 'negate' program twice (once with using the invoke macro (nice and readable) and once without ) to show you the difference
This was awesome =). You are making me want to learn ASM more and more. But first i have to learn Java just for kicks :/
Wanna hear something really awesome?
What i'm working on right now in ASM, for WHATEVER reason my AVG thinks is a Trojan! XD
Quote Originally Posted by B1ackAnge1 View Post
Wanna hear something really awesome?
What i'm working on right now in ASM, for WHATEVER reason my AVG thinks is a Trojan! XD
The AI program from a little while ago came up as a virus when i tried to download it :/ And a program i made also came up as a virus for no reason. Don't remember which one tho. I wonder what criteria these antiviruses use to detect stuff. That's why i can't bother with 'em. Too many false positives. I don't need it anyway.
Quote Originally Posted by zeco View Post
The AI program from a little while ago came up as a virus when i tried to download it :/ And a program i made also came up as a virus for no reason. Don't remember which one tho. I wonder what criteria these antiviruses use to detect stuff. That's why i can't bother with 'em. Too many false positives. I don't need it anyway.
Well you don't really have to worry unless your downloading a lot of sketchy files. The only other way to get a virus on your system is probably if someone attacked you directly, which no antivirus is gonna stop anyway... =/
Hmmm very nice but the first code need a
Code:
system("pause");
before
Code:
return 0;
if u don't have that the console app will flash very very quicly on ur screen and u will can't see nothing
Yeah thanks, however:

a) the cpp code was a mere illustration and comparison against assembly source to show how few lines are required in higher level languages and not meant to be compiled/run.

b) It's a console app, so running it from the console which is how it's intended to run wouldn't have the issue of it closing after running. (though I'm fairly sure most people on this board don't know how to work in the console)

c) system("Pause") is evil. Getch() or something equivalent would be better suited if one were to insist on running it by double clicking it.

d) see a

but hey glad someone actually read this section for change
Yep i agree with u but i use
Code:
system("pause");
Posts 1–12 of 12 · Page 1 of 1

Post a Reply

Similar Threads

Tags for this Thread

Talk with us