Sunteți pe pagina 1din 59

::/\::::::.

:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.Dec98/Jan99
:::\_____\::::::::::.Issue2
::::::::::::::::::::::.........................................................

ASSEMBLYPROGRAMMINGJOURNAL
http://asmjournal.freeservers.com
asmjournal@mailcity.com

TABLEOFCONTENTS

Introduction...................................................mammon_

"KeygenCodingCompetition".................................Ghiribizzo

"HowtoUseA86forBeginners".................................Linuxjr

"UsingtheGnuASAssembler"...................................mammon_

"AGuidetoNASMforTASMCoders"..................................Gij

"TipsonsavingbytesinASMprograms"...................LarryHammick

Column:Win32AssemblyProgramming
"ASimpleWindow".........................................Iczelion
"PaintingwithText"......................................Iczelion

Column:TheCStandardLibraryinAssembly
"The_Xprintffunctions"....................................Xbios2

Column:TheUnixWorld
"XWindowsinAssemblyLanguage:PartI"...................mammon_

Column:AssemblyLanguageSnippets
"IsASCII?"............................................TroyBenoist
"ENUM,CallTable"..........................................mammon_

Column:IssueSolution
"PESolution"...............................................Xbios2

+++++++++++++++++++++++IssueChallenge++++++++++++++++++++
WritethesmallestpossiblePEprogramthatoutputsitscommandline

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::..............................................INTRODUCTION
bymammon_

Wow!Thisissueishuge.Morethantwicethesizeofthelast;maybeitistime
togomonthly...

Thisissuehasasitsthemesuchasitweretheuseofpopularfreeand
sharewareassemblers.ItbeganwithmyneedingtowriteaGASintroto
accompanymyXWindowsarticle;shortlythereafter,Linuxjremailedmethe
benefitsofhisuniversitytrainingwithhisA86tutorial(beginners:thisis
foryou!Linuxjrexplains*everything*).IthenappealedtoGijtoallowmeto
incorporatehisNasm'QuickStart'guiide,whichIhaveusedoften...heposted
theconditionthatIedititheavily;)

Iwouldliketodrawyourattentionfirsttoournewcolumn:AssemblyLanguage
Snippets.OriginallythiswasanideawhichIandafewothershad;however,I
neverreceivedanycontributionsforthe'Snippets'section.ThenIreceivedan
emailfromTroywiththefirstone...Ipulledtherestoutofmyvariousasm
sourcesandvoila,anewcolumnwasborn.Thisissomethingthatisfullyopen
tocontributions;asmsnippetsandwewillneedlotsmaybeemailedto
asmjournal@mailcity.comormammon_@hotmail.com,ortheymaybepostedtothe
MessageBoardathttp://pluto.beseen.com/boardroom/q/19784/
Basicformatshouldbe:
;Name: Nametotitleyouwith
;RoutineTitle:Nametotitlethesnippetwith
;Summary: OneLineDescription
;Comaptibility SpecificAssemblersorOSesthisworkswith
;Notes: Anyextranotesyouhave
Code

Ishouldpointoutherethatfreeservers.comisnotveryreliable;thusthe
APJhomepageisinaccessiblemoreoftenthannot.ForthisreasonIhaveset
upamirroronmyownpage,athttp://www.eccentrica.org/Mammon/APJ/index.html

Asforthisissue'sarticles,weonceagainhavetwofineWin32asmtutorials
byIczelion,whomaintainsanexcellentpageathttp://iczelion.cjb.net(with
aWin32asmmessageboard!).GhirribizzohassuppliedhisfunKeyGenerator
Competitionresults(Ican'tsayIwassurprisedwhenIsawthewinner;).

LarryHammickwhoalsomaintainsanexcellent,smokingenabledpageat
http://www3.bc.sympatico.ca/hammick/hascontributedafantasticpieceonasm
optimization.XBios2hasthistimegoneaboveandbeyond,notonlywiththeC
LanguageinAssemblybutwithhisIssueChallengeaswell...asmcodersand
reverseengineersalikeshouldreadthis.

Asfortheissuechallenge,XBios2didnotprovidemewithonefornextissue,
soIusedonefromatextIfoundontheInternetsomewhere...hehasbeen
emailedthetextandcantrytobeatit;)Also,Iamgoingtobesettingupa
pageforreaderresponsestotheIssueChallengesreaderscananticipatethe
solutionsbeforeeachissuecomesout,ortryandbestthesolutionafterwards.
SubmissionscanbesenttothesameplacesastheSnippets.

AuthorBio's?Iknowmainstreammagsdothisifyouwantone,sendone.I'll
tackitontotheendofthearticle...anythingwithinreason:URL,email,
hobbies,perversions,favoritedrink,favoritelinuxdistro,etc.

NextIssue:HowmanyarticlesonCodeOptimizationcanIget?Thatwouldmakea
greattheme(withthefoundationlaidthisissue)anythingfromcodetheoryto
PentiumIIspecificoptimizationswouldbewelcome.Prospectivearticles,send
tomeorpostontheMB...notopicisunacceptableunlessyoucaninnoway
possiblerelateittoassemblylanguage.

Enjoytheish,
_m

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::...........................................FEATURE.ARTICLE
KeygenCodingCompetition
byGhiribizzo

Introduction

Thecompetitionwastowritethesmallestkeygeneratorforthesimpleserial
schemeIwroteasatrainerfornewbies.Ihadafewreasonsforstartingthis
competition:
oTogivethenewbiesachancetoparticipateinacompetition
oTogiveoldhandsthechancetobrushupontheirassemblyskills
oTopromotetightassemblycoding
oTodemonstratethevariousdifferentmethodsusedtoimproveefficiencyin
coding

Well,I'mbackfrommyshortEuropeanjauntandthecompetitionisnowclosed.
Ihavegreatlyenjoyedtheentirecompetition,fromthecodingofthecrackme
andthechatswithvariouscrackersonIRCthroughtodecidingthewinnerand
writingthisdocument.

AnalysisoftheSerialScheme

Theserialschemewaskeptdeliberatelysimpleasitwaswrittenfornewbiesto
trainwith.Theschemetookanameofupto16byteslongandrequireda16
byteserialnumber.Therewasa256bytelookuptablethatwasindexeddirectly
withtheASCIIvaluesofthenamefield.Thenamewaspaddedtoalengthof16
(ifnecessary)usingvalueshardcodedintothescheme.The256bytelookup
tablewascreatedusingeightmaximal8bitlinearfeedbackshiftregisters
(LFSRs)inparalleli.e.producingoneoutputbyteper'clock'.TheLFSRswere
initialisedtoproduce'Ghir_OCU'asthefirst8outputbytes.Thetablewas
precomputedanditwasnotexpectedthatthecrackerrecognisethenatureof
thelookuptablealthoughapostImadetothecrackingforumaboutLFSRs
mighthavetippedthemoreastutecrackers!

Therulesofthecompetitionrequiredthatsomestandardinterfacetextbe
includedwhichstronglyurgedtheuseofservice9interrupt21hthoughthis
wouldprobablybeusedinanycaseanddiscouragedblankscreensandother
unfriendlyUIsfrombeingusedtosavebytes.Also,therulesspecifiedarange
ofinputtobehandledsmallerthanthepossible256maximum.Duetothesimple
natureoftheserialscheme,thismeantthatthelookuptablecouldimmediately
bestrippeddowntotheinputrange.

Ienvisionedthattherewouldbe3'fights'.Onetoreducetheoriginal
algorithm,secondtoreducethepackedtablelookupalgorithmandthelastto
reducetheLFSRalgorithm.Asitturnedit,everyoneseemedtogoforthe
packedtableoption.

TheEntrants

Thefollowingentrantshavebeenincludedbecausetheyillustratethedifferent
ideasandmethodsusedtoreachthecommongoalofreducingcodesize.Ididn't
realisethatsomanycrackerswouldusetheprecomputedtablemethod.Perhaps
wordgotoutduringIRCchatsandeverybodystartedusingthem?Inanycase,
thisdidn'treducethesizecuttingwarasprecomputationhaditsownroutines
thatneededtobeoptimised.

GhiribizzoAlpha(223bytes)

Thiswasnotanentrantasitwouldhardlybefairformetoenterthe
competitionknowinghowthelookuptablewasgenerated!Thiskeygenwas
basicallyconvertedfromthecrackmeandimproved'onthefly'bygenerating
thelookuptableincodeandtidyinguproutineswheretheywereobviously
inefficient.Nogreatthoughtwentintothisandthecodesizewasjusttogive
myselfanideaofwhatcrackerswouldbeaimingfor.Asidefromgeneratingthe
lookuptable,theonlyotherunusualfeatureofthiskeygenwastheuseofthe
XLATcommandinsteadofthestandardindexingusedinthecrackme.Ididn't
stoptocheckwhetherthisusedlessspaceornot,butincludeditasnewbies
maynotbefamiliarwiththeXLATinstruction.Asithappened,theXLAT
instructionwasusedinSpyder'skeygen.

FromthesizeIgotfromthiskeygen,Itriedtoguessarequiredkeyinput
rangetoputthissizebetweenthestraighttableprecomputationandthepacked
tableprecomputation.

OnethingtonoteishowIendedtheprogram.Iwasquitesurprisedbythefact
thatnobodyelseseemedtoknowthatyoucouldquitcomprogramswitharet
instruction.FurthersizesavingscanbemadebyusingBb'strickofkeepingDH
andalsobytweakingthegeneratortofixsomeofthebitstreamsproducedto
giveusthebitsweneedandsavelaterprocessing.

CrueheadAlpha(244bytes)

IgotthisfromCrueheadonIRCwhenIaskedtoseewhathehadmanagedsofar.
Althoughthisversionisunfinisheditisstillimpressive.Thekeygenrelies
onprecomputingthewholetableandreducingthekeygentoasingletable
lookup.

ThecodingisverysimplealmostseemsasifCrueheadwastypingthesteps
goingthroughhisheadstraightontothekeyboard(perhapshewas?)the
resultingcodeisconsequentlyveryeasytounderstandandfollow.

Bb#10(230bytes)

Bbhaswrittenanexcellentkeygen.Hehasputsomeserioushardworkintothis
includingtakingthetimetocalculatethedxoffsetsmanuallyinsteadofjust
usingthe'offset'featurethatthecompilerprovides.Ithasbeenfunwatching
Bb'skeygenprogressasthefirstoneIreceivedwasversion5whichwas256
byteslong.Thekeygenpresentedhereisversion10.Thereareothernicebits
andbobsthroughoutthiscode.Thismakesitquitefrustratingasinvarious
placessomuchspaceisblatantlywasted.Justtakealookatthelast6lines
ofcode!Thereshouldn'tevenbe6linesthere!I'msureBbwilllearnalot
fromseeingsomeoftheotherkeygenshereandI'msurehewilldoverywell
shouldheenterthenextcompetition.

Spyder(211bytes)

Tidy,compactandelegantlycoded.Alittlesparseincommenting(itseemslike
SpydercoercedIDAtowritethekeygenforhim;p).Thetablelookupisan
interestingpieceofcode.

VoidLord(247bytes)

Anotherkeygenusingtheideaofapackedprecomputedtable.VoidLord'sfirst
keygen.Let'shopeweseemore!

HonourableMentions

SpecialmentiongiventoTrykkawhomanagedtodeducehowthelookuptablewas
createdbutneversentinanentry!

TheWinner

WellitlookslikeSpyderisthewinnerbyquitealargemargin.Incidentally,
Ihavejustmadeaquickcheckthatthekeygenswork.Youmightbeabletobump
yourselfuponthescalebypickingholesintheotherkeygens:)

Rankings

__Keygen______Size________Author______
kgen.com 211 Spyder
kg.com 224 Ghiribizzo(alpha)
kg10.com 230 Bb
kg9.com 233 Bb
kg6.com 239 Bb
kgvoid.com 247 VoidLord
kgcrue.com 255 Cruehead(alpha)
kg5.com 256 Bb
kgt.com 529 SerialScheme

FinalWords

Therehavebeensomeexcellentideasinthekeygens.However,noneofthe
keygensareassmallastheycouldbe.Theyallhavesomescopeforimprovement.
Bycombiningsomeoftheideasgivenintheabovekeygens,wecouldcreatea
newsmallerkeygen.Itwillbeinterestingtoseewhatthesmallestpossible
keygenwouldlooklike.

Ihopethateveryonewhohastakenpartinthecompetition,orwhohasfollowed
it,hasgainedsomethingfromit.Ihopethattherewillbemoreentriesfor
thenextcompetition!

TheSourceCodes

;Ghiribizzo'sKeygen=========================================================
.modeltiny
.386
.code
.startup
;Thefirstpartofthecodeisthetablegenerator
;Notethatwecanactuallydosome'precomputing'by
;fixingsomeofthebitsinthegeneratortoproduce
;thebitsthatweneed.Thiswillsavesomebytes
;intheserialsection.Ihavenotbotheredtodothis.
movax,5547h
movbx,6869h
movcx,725fh
movdx,4f43h
movdi,offsetPRD
movsi,offsetPRD+0ffh
LFSR:
stosb
;SaveMSB
movbp,ax
moval,ah
andax,0ffh
xchgax,bp
;Tap
xorah,bl
xorah,ch
xorah,al
;Shift
moval,bh
movbh,bl
movbl,ch
movch,cl
movcl,dh
movdh,dl
;StoreMSB
anddx,0ff00h
ordx,bp
cmpdi,si
jleLFSR
;
movah,9
movdx,offsetstartMsg
int21h
movah,10
movdx,offsetNameInput
int21h
;
movsi,offsetNameBuffer
movdi,offsetNameHash
movbx,offsetTable1
MakeSerial:
lodsb
xlat
andal,3fh
oral,30h
byteOK:
cmpal,39h
jlekeepit
addal,7
keepit:
stosb
cmpdi,offsetstopbyte
jlMakeSerial
;
movdx,offsetNH2
printMsg:
movah,9
int21h
exit:
ret
StartMsgdb 0dh,0ah,'OCUKeggen#1',0feh,'Ghiribizzo1998',0dh,0ah
db 0dh,0ah,'EnterName:$'
NameInputdb 17
NameReaddb ?
NameBufferdb 'mk3"![]ns)%3x#0Z'
nh2 db 0dh,0ah,'SerialNumber:'
NameHashdb 16dup('y')
stopbytedb 0dh,0ah,'$'
Table1:
PRD:
END

;Cruehead'sKeygen===========================================================
.modeltiny
.386
.stack
.data
StartMsgdb 0dh,0ah,'OCUKeggen#1',0feh,'Cruehead1998',0dh,0ah
db 0dh,0ah,'EnterName:$'
SerialMsgdb 0dh,0ah,'SerialNumber:'
NameVardb 011h,0h,06Bh,06bh,033h,020h,022h,021h,05bh,05dh,06eh
db 073h,029h,025h,033h,078h,023h,030h,'$'
Table db 037h,035h,034h,031h,036h,032h,046h,044h,046h,044h,044h
db 031h,035h,035h,038h,035h,036h,046h,032h,045h,036h,030h
db 031h,039h,033h,034h,030h,046h,031h,042h,044h,030h,043h
db 036h,043h,035h,039h,045h,039h,033h,036h,043h,037h,035h
db 036h,044h,045h,036h,032h,044h,031h,037h,039h,030h,031h
db 042h,046h,043h,034h,032h,031h,035h,037h,034h,044h,032h
db 032h,032h,030h,043h,034h,030h,044h,044h,033h,039h,044h
db 043h,038h,036h,031h,038h,041h,037h,034h,046h,045h,041h
db 036h,044h,043h,041h,041h,039h,043h,037h
.code
.startup
movah,09h
leadx,StartMsg
int21h
movah,0ah
leadx,NameVar
int21h
OnceAgain:
movbl,NameVar[di+4]
cmpbl,0dh
jnenoprob
movbl,02bh
noprob:
moval,table[bx020h]
movNameVar[di+2],al
incdi
cmpdi,0Eh
jneOnceAgain
movwordptrNameVar[16],00a0dh
movah,09h
leadx,SerialMsg
int21h
.exit
end

;Bb'sKeygen=================================================================
;KG10GhiribizzoKeyGen
;writtenbybb12Sep981:30AM
;nextrevision13Sep985:00PM
;yetmorechanges26Sep98latelatenight
;eat3morebytes28Sep98
;
;commentswheretheevilslay
;
;IjustknewthatIHADtomakethisthing256bytesofless.Beware:This
;isNOTanexampleofgoodcodingpractice!IalmostwishIcoulddoa
;"bytessaved"comparisonforallthelittlehacks.
;
;I'vegottenthistoassembleunderTASM.ItMUSTassembleasa16bitCOMfile,
;andeventhenIcan'tguaranteethattheoffsetswillremainstablebetween
;variousassemblers.Letmerestatethat:ICANguaranteethatthiswon't
;workforyouwhenyoutryandassembleityourself.:)
;
P8086
MODELTINY
DATASEG
OffsetStartMsg EQU52h
OffsetMySerial EQU7fh
OffsetSerialMsgEQU91h
OffsetMyName EQU0a3h
StartMsgdb 0dh,0ah,'OCUKeggen#1',0feh,'bb1998',0dh,0ah
;There'snoreasonnottoreusethissectionoftheStartMsg,sinceitfits
;perfectlythoughcodehadtobeaddedtoaffixalinefeed
MySerialdb 0dh,0ah,'EnterName:$'
SerialMsgdb 0dh,0ah,'SerialNumber:$'
;previouschangetoMyNamenotneededanymore
MyName db 11h,0h,6Dh,6Bh,33h,20h,22h,21h,5Bh,5Dh,6Eh,73h,29h,
db 25h,33h,78h,23h,30h,5Ah
;Notonlydoesthefulltablenotneedtobeused,butsinceit'sbasicallya
;substitutioncypherwecanfiteverythingintothese96orsobytes
;Also,thetrailingcommentedout37hsavesusonebyte.It'sthesubstitutionfor7Fh,
;butsince7FhisaDELETEwhenusing0a/int21h,itnevergetsacceptedbyKGT.COMorby
;thiskeygen.Therefore,it'suselessandunneeded.
;NewTabledb'754162FDFDD155856F2E6019340F1BD0C6C59E936C756DE62D17901BFC421574
;D2220C40DD39DC8618A74FEA6DCAA9C';,37h
;andImissedthefactthatitalsoonlyusescharacters09andAF
;whichcanbeexpressedin4bits,cuttingthe96bytetableinhalf

NewTabledb 75h,41h,62h,0FDh,0FDh,0D1h,55h,85h
db 6Fh,2Eh,60h,19h,34h,0Fh,1Bh,0D0h
db 0C6h,0C5h,9Eh,93h,6Ch,75h,6Dh,0E6h
db 2Dh,17h,90h,1Bh,0FCh,42h,15h,74h
db 0D2h,22h,0Ch,40h,0DDh,39h,0DCh,86h
db 18h,0A7h,4Fh,0EAh,6Dh,0CAh,0A9h,0C7h
CODESEG
STARTUPCODE
;Anotehere:We'reat<256bytesandwefitsnuglybetween0100h0200hinmemory.
;Therefore,anyoffsettotextthatweneedisgoingtohaveaconstantvaluefor
;DH,namely01h.ByinitializingDHonceatthisnextlineofcode,weneverneed
;tochangeDHagain,onlyDL.We'llsaveafewbyteshereandtherebecauseofit,
;thoughit'smoreworktofindtheoffsetsmanuallyafterassembly,andthenhard
;codingtheminandreassembling.Isupposetheremightbesomeconstructlike
;offset(MyNameAND00ffh),butIdidn'treallylookintoit.EQUwillwork.
movdx,offsetStartMsg
movah,09h
int21h
;saveabyte
movdl,OffsetMyName
movah,0ah
;Nowthatwe'rethroughwiththeStartMsg,wecanadjustMySerialtoprintalinefeed.
;IcansaveabyteherebyusingtheAHregisterinsteadofa0AHimmediatevalue,
;sinceAHisnowsetto0AHfortheint21getstringfromkeyboard.
mov[MySerial+10h],ah
int21h
;2intoDLforadivisionduringthemainloop
movdl,2
;WestartattheENDofMyNameandworkourwaybackwards,becausewecanavoidtheCMP
;andsimplycheckfortheSignedflagwhenBProllsover.Wesaveacoupleofbytes.
movbp,0fh
;Also,IshavedafewbytesoutofthisbyusingBPinplaceofBX,avoidingthePUSH/POPs
;whichIshouldn'thavedoneanywaysinceIdidn'tdefineanewstackfortheapplication.
loop1:
xorah,ah;needtoclearahandbh,unfortunately.
xorbh,bh
moval,[bp+MyName+2]
subal,20h;ifthesubsetscarry,thenwe'reprobablythecarriagereturn
jncskipcr;sowe'llsetourselves=tosomethingthathasthesametable
moval,03h;lookupvalueasthecarriagereturn.
skipcr:
divdl;aftertheDIV,ALwillbetwotablevalues,andAHwilldecidewhich
;oneweshoulduse
movbl,al;weneedtablelookupthroughbx,notal
moval,[bx+NewTable]
testah,dh;sincedhalways=1,testah,dhwillsaveusabyteovertestah,01
jneskipshift;ifAH=0,useleastsignificantnibble
;ifAH=1,usemostsignificantnibblebyshiftingMSNintoLSN
;TASMassemblesshral,4asshral,1fourtimes..wedon'twantthat.
db0c0h,0e8h,4;shral,4
skipshift:
andal,0Fh;stripoffhighnibble
addal,30h;andturnintoprintable[09AF]character
cmpal,39h
jlenumnum
addal,7
numnum:
mov[MySerial+bp],al
decbp
jnsloop1;loopuntilbpflips
;saveanother"offset"byte
movdl,OffsetSerialMsg
movah,9
int21h
;saveanotherbyte
movdl,OffsetMySerial
;AHshouldalready==9,noneedtospecifyithere.
int21h
;Endoftheline
movah,4ch
int21h
END

;Spyder'sKeygen==============================================================
;Ghiribizzo'sKeyGeneratorCompetitionentrybySpyder
;Sheeshyougetassemblersourceandyouwantcomments?
;Onlyonenibbleofeachbyteintheoriginalkeytableholdsuseful
;information.Onlykeytableentriesintherange20..0x7Fand0x0Dare
;neededthose60nibblesarepackedintoa30bytetable,0x0Dishandled
;asaspecialcase.
;Therestisjustspaceconciousassemblerwithafewwrinklestosave
;bytes.IworryImayhavemissedsomepatterninthekeytable,couldit
;begeneratedorderived?OtherwiseI'mprettyhappywiththeresult.
.286
seg000segmentbytepublic'CODE'
assumecs:seg000
org100h
assumees:nothing,ss:nothing,ds:seg000
publicstart
startprocnear
movah,9
movdx,offsetStartMsg
int21h;Signon
movah,0Ah
movdx,offsetBuffer
int21h;Getname
movsi,offsetBufferCont;Setupforloop
movdi,offsetSerial
movbx,offsetKey10h
xorax,ax
movcx,10h
loop1:
lodsb
;cmpal,0dh;don'tneedthisbecausewearrangedthedata
;jnzskip0;beforethekeytabletogivetherightcode
;moval,'p';forthisoutofrangecase
skip0:
saral,1
xlat
jcskip1
saral,4
skip1:
andal,0fh
addal,'0'
cmpal,'9'
jleskip2
addal,7
skip2:
stosb
looploop1
movsw
movsb
movah,9
movdx,offsetSerialMsg
int21h
int20h
startendp
Buffer db 11h;
db 0;
BufferContdb'm'
db'k'
db'3'
db''
db'"'
db'!'
db'['
db']'
db'n'
db's'
db')'
db'%'
db'3'
db'x'
db'#'
db'0'
db0dh,0ah,'$'
StartMsgdb0dh,0ah,'OCUKeggen#1',0feh,'spyder1998',0dh,0ah
db0dh,0ah,'EnterName:$'
db0;Acrucialspacer
Key db075h,041h,062h,0FDh,0FDh,0D1h,055h,085h
db06Fh,02Eh,060h,019h,034h,00Fh,01Bh,0D0h
db0C6h,0C5h,09Eh,093h,06Ch,075h,06Dh,0E6h
db02Dh,017h,090h,01Bh,0FCh,042h,015h,074h
db0D2h,022h,00Ch,040h,0DDh,039h,0DCh,086h
db018h,0A7h,04Fh,0EAh,06Dh,0CAh,0A9h,0C7h
SerialMsgdb0dh,0ah,'SerialNumber:'
Serial:
seg000ends
endstart

;VoidLord'sKeygen============================================================
;OCUKeygen#1|VoidLord1998
;Category:newbie(thisismyfirstkeygen)
;Solution:
;fortheeverypossibleinputchar(20h7fh)the"serial"charisstoredinthe
;Table.Sincetheoutputcharscanonlybe09andAF,wecanstoretwochars
;inonebyte,reducingthetablesizeto48bytes.
seg000segmentbytepublic'CODE'
assumecs:seg000
org100h
assumees:nothing,ss:nothing,ds:seg000
startprocnear
movah,9;DOSWritestartingmessage
leadx,StartMsg
int21h
movah,0ah;DOSreadName
leadx,Serial
int21h
xorax,ax
xorbx,bx
loop1:
moval,[Serial2+bx];theoutputwillbeinthesamebuffer
cmpal,0dh;endofinputstring(odh)?
jneno_cr
mov[Serial2+bx],'1';theoutputcharwillbe'1'
jmpfinish;theremainingcharsareOKalready
no_cr:
pushbx;nowweshouldtranslatethenamechar
subal,20h;totheserialnumberchar,usingthe
movbx,ax;lookupTable
shrbx,1;wehavetwocharsinonebyteintheTable
andal,1
jnzodd;isthischar"evenorodd"?
moval,[Table1+bx]
andal,0fh;ifeven,usethelower4bits
jmpend_l
odd:
moval,[Table1+bx]
movcl,4
shral,cl;ifodd,usethehigher4bits
end_l:
popbx;translatethenumbertothehexchar
cmpal,10;isitdigit09orletterAF
jldigit
addal,7;ifletter,add7
digit:
addal,'0';ifdigit,justadd'0'
mov[Serial2+bx],al
incbx;processnextinputchar
cmpbx,10h
jlloop1
finish:
movSerial,':';completetheoutputstring
movSerial+1,''
movah,9;DOSPrintsolution
leadx,SerialMsg
int21h
movah,4Ch;DOSQUITwithEXIT
int21h
startendp
StartMsg db 0dh,0ah,'OCUKeygen#1',0feh
db 'VoidLord1998'
db 0dh,0ah,0dh,0ah,'EnterName:$'
SerialMsg db 0dh,0ah,'SerialNumber'
Serial db 11h,0
Serial2 db 67,57,69,55,52,53,50,53,56,55
db 68,50,69,54,49,54,0dh,0ah,'$'
Table1 db 87,20,38,223,223,29,85,88,246,226
db 6,145,67,240,177,13,108,92,233,57
db 198,87,214,110,210,113,9,177,207,36
db 81,71,45,34,192,4,221,147,205,104
db 129,122,244,174,214,172,154,124
seg000ends
endstart

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::...........................................FEATURE.ARTICLE
HowtoUseA86forBeginners
byLinuxjr

Requirements:
BasicDosknowledgelikecopyingandrenamingfilesandsuch

IamwritingthispaperforIfindplentyoftutorialsandbooksallabout
assemblyandhowtowriteprogramsandhowtodoloops,if/elsestatments,
etc...ButonethingIdidnotseeplentyofistutorialsonhowtosetupthe
assemblerofchoicethatyougrowfondof,forinstancenasm,a86,tasm,masm
GAS,etc.

SoIamwritingabouta86andI'musingmycollegenotesandexperienceI
learnedfrommyAssemblyclass.Ihopethiswillhelpyouenjoya86and
encourageyoutolearnhowtomanageuptox286opcodesand16bitcode
beforeyoustarttacklingwith32bitandWindowsprogramminginassembler.
ThisisasortofwarningthatyouwillonlybeabletowriteDOSprograms
butyouhavetolearnhowtocrawlbeforeyoucanwalk,andyouhavetolearn
howtowalkbeforeyoucanrun.Ihopetoshowyouhowtosetupa86,how
towriteafewsimpleprogramswiththetemplateIuse,andhowtodosome
basicstuffinassembler.

ItookacollegecourseonAssemblyacoupleofmonthsago,andIwashappyto
learntheinternalsofthesystemandhowtomanipulatetheregistersforsome
awesomeresults.Theassemblerthatweusedwasa86byEricIsaacson.This
isasharewareprogram,meaningyougettoplaywithitbeforebuyingit.To
getthisassemblergotohttp://www.eji.com/a86/andyouwillseewhereto
downloadtheprograms.Itisinazipfileandyoujustunzipitwithyour
favoriteprogramlikewinziporpkunzip.Youshouldalsodownloadd86,the
debugger,forusewithyoura86programs.Onceyoudownloadedthem,unzipthe
filestoadirectorysuchasc:\a86,orevenputonafloppydiskifyouare
worriedaboutspace.

GettingStarted

Let'sgetintoit:you'vegottheassemblerandthedebugger,whatnext?First
ofall,wehavetomakeatextfilesinceallasmsourcecodeisnothingbuta
plaintextcodethathasabunchofoperandsandfunctionstodowhatyouwant
yourprogramtodo.

Istartallmya86programmingbyopeningupmytemplate.asm,whichwhatI
gotfromschool;itisausefultemplateanditmakesagooddos.EXEwhenyou
compileitwiththesuppliedbatchfile.Cutthefollowingcodeandsaveitin
atextfilecalledtemplate.asm:

XBeginCuttinghere

;PROGRAM :
;
;AUTHOR :
;
;PURPOSE :
;
;PROGRAMOUTLINE:
;
;==============================EXTERN===============================

;===========================STACKSEGMENT===========================
ssegsegment parastack'STACK'

db 100Hdup(?) ;allow256bytesofmemoryfor
;usebyourprogramstack.
ssegends

;============================DATASEGMENT============================
dseg segmentpara'DATA'

dseg ends

;============================CODESEGMENT============================
cseg segmentpara'CODE'
;BegintheCodesegmentcontainingexecutablemachinecode

programproc far ;Actualprogramcodeiscompletely


;containedintheFARprocedure
;namedPROGRAM

assume cs:cseg,ds:dseg,ss:sseg
;SetDataSegmentRegistertopointtotheDataSegmentofthisprogram
mov ax,dseg
mov ds,ax

;===============RestofMAINPROGRAMcodegoeshere==================
exit:
mov ax,4c00h ;terminateprogramexecutionand
int 21h ;transfercontroltoDOS

programendp ;endoftheprocedureprogram

;============================PROCEDURES==============================
cseg ends ;Endofthecodesegmentcontaining
;executableprogram.

end program ;ThefinalEndstatementsignalsthe


;endofthisprogramsourcefile,and
;givesthestartingaddressofthe
;executableprogram

XStopCuttinghere

Nowwehaveatemplatetouse,andthisisjustoneoutofmanytemplatesyou
canmakeforyourassemblyprograms.Nowlet'sbegintohavefun.Thesefew
programswillgetusgoingforabasicfeelofhowtosetupabasichello
program.

Whatwewilllearnfromthisexampleis:
1)ThebasicmechanicsofeditingthetemplatefiletogetanASMsourcecode
file,assemblingandlinkingit,andpossiblyfixingsyntaxerrors.
2)Nearlyalloftheprogramshaveloopsinthem,havingdifferentformats.
3)TheoperationofseveralINT21Hfunctions:01H,02Hand08H
(characterinputandoutput),09H(stringoutput),and4CH(programtermination)
4)TheoperationoftheDOSIOLTprocedures:inhex16andouthex16,andhowto
assembleandlinkaprogramthatusesthem.
5)Bothstringandnumericvariableswillbedemonstrated.

CreatinganASMfilefortheMessageProgram

Tobecomefamiliarwiththeprocessofcreatinganassemblyprogram,youwill
createasimpleprogramthatprintsaonelinemessage.Aswithmost
programminglanguages,Assemblyprogrammingstartswithaplaintextfile
containingtheprograminstructionstoexecute.Ordinarily,aprogrammerwould
havetotypeintheentiresourcefilefromscratch.But8086assembler
programfilescontainalargenumberofsetupdirectivesanddeclarations
whichareessentiallythesameforeveryprogram.Itwillbeeasiertostart
withafilethathasallthenecessarydirectivesanddeclarationsalreadyin
it,andjustaddtoittheactualprogramparts.

Thefiletemplate.asmisthatatemplatewhichcontainsallthenecessary
piecesofaprogram,exceptfortheactualprogramitself.Makeacopyofthe
template.asmfile,andnameitsomethingappropriate:message.asmisagood
choice.ThefileextensionmustbeASM.Youwilleditthenewfiletocreate
yourfirstprogram.DONOTEDITtemplate.asmitself!!!!Youwillusethis
templatefileasthestartofyourassemblyprogramssoitshouldnotbe
alterated(untilyougetadvancedenoughtoplayaroundwithit;).

WewillbeusingEDITinadosboxasoureditor,thoughyoucanusenotepador
Ultraedittoedityourassemblyfilesaswell.

TheComments
Alloftheprograsthatyouwillwriteshouldhaveadescriptivesetofheader
commentsatthetop.AnytextAFTERasemicolonisconsideredacomment.The
topofyournewprogramfileshouldalreadyhavethebasicoutlineforthis
comment.Editinyourmessage.asmfiletohavesomethinglikethis:

;PROGRAM :MessageProgram
;
;AUTHOR :YourNamehere
;
;PURPOSE :Thisprogramsimplyprintsaonelinemessage
; tothescreen
;PROGRAMOUTLINE:UseINT21HFunction09Htoprintthemessage.

Thisisjustanexampletohelpyouknowwhatyouwanttodo,andtohavea
referenceifyouweretowalkawayfromaprojectforayearorso...theheader
willmakeanicereminderofwhatyouweretryingtogetthisprogramtodo.

TheRamVariable
Theprogramthatyouwillcreatinthispartrequiresavariable.Youwill
createastringofcharacterslabeledmessage.Thepartofthefilewhereall
dataisplacedistheDataSegment.LookinyourASMfileforthefollowing
lines:

dseg segmentpara'DATA'

dseg ends

Changethispartofthecodesothatthemessagetobeprintedisdefined.
Theresultwilllooklike:

dseg segmentpara'DATA'

messagedb0DH,0AH,"WHOPPEEEE!!!MyfirstMessage.",0DH,0AH,"$"

dseg ends

TheHEXvaluesarethetwobytesequenceforaDOSnewline(CRLF).Thefirst
charactersof"0DH"and"0AH"isZERO,nocapitalO.NotethatthereisNO
semicolonbefore"message".Donotallowthisparttobreakovertwolines.

THECode
Nowlocatethepartofthecodewheretheprogramcodegoes.Itshouldlook
likethis:

;========================MainProgram================================
;
programproc far ;Actualprogramcodeiscompletely
;containedintheFARprocedure
;namedPROGRAM

assume cs:cseg,ds:dseg,ss:sseg
;SetDataSegmentRegistertopointtotheDataSegmentofthisprogram
movax,dseg
movds,ax

;===============RestofMAINPROGRAMcodegoeshere==================

exit:
mov ax,4c00h ;terminateprogramexecutionand
int 21h ;transfercontroltoDOS

programendp ;endoftheprocedureprogram

;============================PROCEDURES==============================

cseg ends ;Endofthecodesegmentcontaining


;executableprogram.

end program ;ThefinalEndstatementsignalsthe


;endofthisprogramsourcefile,and
;givesthestartingaddressofthe
;executableprogram

AllofthecodeforyourprogramShouldREPLACEthecomment:
"RestofMainProgramcodegoeshere".

Hereisthecodeyouwillusetoprintoutthemessage:

;Printthemessage
movdx,offsetmessage
mov ah,09H
int21H

ThiscodejustcallstheDOSInterruptusedtoprintstringstothescreen.
Interrupt21HisageneralstartingpointformanyusefulDOScalls.The
subfunctionusedtoprintstringsisFunction09H;thisvaluemustbeloaded
intotheAHregisterbeforecalling.Also,Int21HFunction09Hrequiresthe
addressofthemessagebeplacedintheDXregister.Theabovecodeperforms
thesetwoinitializationtasks,andthencallstheinterrupt.

Takecarefulnoteofthesemicolonswhichstartthecomments.Also,donot
alteranyoftheotherpartofthecode.

Theseweretheonlytwochangesyouneededtomake.

Assemblingwithasm86.bat

Nowwehavewrittenourfirstasmfile.Toassemblewitha86youcouldtryto
usetheswitchesfromthemanualthatisincludedwiththea86package,or
youcanmakethingseasybyusingthisbatchfile,whichisdesignedfor
programsthatusethetemplatefile.Hereisthebatchfile:

:ASM86
@echooff
REMThisisasimplebatchfiletousea86andlink:
ifexist%1.asmGOTOFOUND
echo%0ERROR:%1.asmFILENOTFOUND
echoUsage:%0file[linkfile]
GOTOSTOP
:FOUND
:Assembletheprogram
echoa86+O+S+E%1.asm
a86+O+S+E%1.asm
::IFTHEREWASANERROR,STOP
IFERRORLEVEL1GOTOSTOP
::IFthereisasecondfilename,assumeitisaOBJfile,
::andlinkittothe%1name.
IFX%2==XGOTOELSELINK
ECHOlink%1+%2;
link%1+%2;
GOTOENDIFLINK
:ELSELINK
echolink%1;
link%1;
:ENDIFLINK
:STOP

andsavethisasasm86.bat.

Allthisdoesis1)createanobjectfile(+O),2)suppressthecreationof
thesymboltable.sym(+S),and3)copytheerrorstoathefilename.errinstead
ofwritinginyourfile(+E).

Toassemblethemessage.asmwiththebatchfile,type
asm86message

Iftherewereanyerrors,youwillhavetoedittheasmfiletofixthem.The
errormessagesdisplayedbytheassemblershouldindicatethelinenumberand
causeoftheproblem.Sinceyouarejustcopyingpregeneratedcode,anyerrors
willsimplybetypos.

Oncealloftheerrorshavebeencorrected,apairoffileswillhavebeen
created.Thewillhavethesamebasenameastheoriginalasmfile,butwill
havedifferentextensions:

OBJObjectfile.Containsthebasicmachinecode,butdoesnothaveany
referencestoexternalprocedures.Thisis,effectively,anintermediatefile
whichisusedbythelinkertoproducethefinalexecutablefile.

EXEExecutablefile.Allexternalreferencesresolved.Completelyrunable.

ToruntheprogramjusttypeMessageandyouwillseethelineappearonthe
screen.

ThiswasasimpleHelloprogram.Whatyouprobablywantisanotherexampleor
twototryout,andthatiswhatweshalldo.ThenextProgramthatwon'tbeas
longbutwillhaveplentyofinfo.

CharLoopProgram

Inthispart,youwillcreateasimpleprogramthataskstheusertoentera
character,andprintsitoutagain.Itdoesthisrepeatedly,untiltheuser
hitstheESCkey.Dosfuntions01Hand02Hareintroducedwiththisprogram,
anditisthefirstprogramcontainingacomparisonloop.

Againyoushouldstartbycopyingtemplate.asmtoafilecalledcharloop.asm.
Editthecharloop.asmtemplatesothatithasthefollowingchanges:

CreatetwomessagesbyaddingthefollowinglinestotheDataSegmentpartof
theprogram(seethemessageprograminstructions,ifyoudon'trememberhow
todothis):

prompt db 0DH,0AH,"EnteraCharacter:$"
outmsg db 0DH,0AH,"YouEntered:$"

Nowaddthecodewhichwillputthefollowing"pseudocode"intoeffect:
Repeat
promptforandreadacharacter
Printthecharacterbackoutwithamessage
Whilethecharacterreadisnotesc

Whichwillturnouttobethefollowingassemblycode:

char_loop:
;Printtheprompt
mov dx,offsetprompt
mov ah,09H
int 21H
;ReadacharacterintoAL
mov ah,01H;(01Hwithecho;08Hnoecho)
int 21H
mov bl,al ;savecharacterinBL
;Printthefinalmessage
mov dx,offsetoutmsg
mov ah,09H
int 21H
;Writethecharactertothescreen
mov dl,bl ;putcharacterindl
mov ah,02H
int 21H
;Loopback,onlyifthecharacterwasnotesc(1BH)
cmp bl,1BH
jne char_loop
;EndRepeat

NotehowthetwonewDOSinterruptsarecalled.TheFunctionnumberisalways
placedinAHbeforecalling,andtheINT21Hinstructionisusedtoinvokethe
interrupt.ForFunction1H,whichreadsacharactertothescreen,theDL
registermustbeinitializedwiththeappropiatevalue.

Notealsothatthecharactermustbestoredsomewherethroughoutthewhole
loop,anditcanNOTbestoredeitherALorDLALismodifiedbyFunction
02H,andDLismodifiedwhenDXissettotheaddressoftehstrings.SoBLis
usedtostorethecharacter,andthevaluemustbetransferredbetweenAL,BL
andDLduringprocessing.Thiskindofjugglinghappensofteninassembly
programming.Getthisprogramrunningtowatchanothergoodprogramgoing;).

CharLoopProgramwithoutEcho

InCharLoopprogramabove.Function01Hwasusedtoreadacharacterfromthe
keyboard.Itdoesmorethanjustreadacharacter,italsoechoesitbackto
thescreen.Thisway,whenyoutypesomething,yougetvisualfeedbackofwhat
youhavedone.

Function08HworksexactlythesameasFunction01H,exceptforthisecho
feature:Function08HdoesNOTechothecharacterafterreadingit.

CreateanewprogramwhichisexactlythesameasCHARLOOP,exceptitshould
useFunction08Htoreadthecharacters,insteadofFunction01H.Writeand
runtheprogramtoseehowitworks.

NumLoopProgram

ThisprogramwillworkinasimilarfashiontotheCharloopprogramabove,but
itwillreadandprintnumbers.SincethereisnoDOSinterrupttoconvert
ASCIIcharacterstonumbers,yourcodewillhavetodothis.Fortunately,
therearealreadyprocedurestodothis.Afewextrastepsmustbetakento
usethem,butitwillbemucheasierthanwritingthecodefromscratch.See
theinfoaboutDOSIOLTfordetailsonhowtousethesprocedures.

DOSIOLTProcedures
HereisadescriptionoftheDOSIOLTprocedures:

inhex16
ThisprocedurereadsaHEXnumberincharacterformatfromthestandardinput,
andconvertsittoaword.SpacesorTabsmayprecedeorfollowthennumber.
DOSint21H0AHisusedtoreadtheinputstring,soitmustbeterminatedbya
RETURN.BothupperandlowercaselettersAFmaybeused.Ifthenumbertyped
islargerthanFFFH,theupperbitsarelost.Ifanythingunpredictableis
typed(likenonHEXchars)thefunctionwillreturnjunk.
Inputs:None
Outputs:AXthewordsizednumberread.
Modifies:AX,flags

outhex16
Thissimpleroutineprintsthefour'nibbles'ofAXasASCIIdigits.
Fourdigitsarealwaysprinted.
Input:AXthenumbertobeprinted
Outputs:None
Modifies:Flags

outHex8
Thissimpleroutineprintsthetwo'nibbles'ofALasASCIIdigits.Twodigits
arealwaysPrinted.
Input:ALthenumbertobeprinted
OUTPUT:NoneModifies:Flags

Call
EachoftheseproceduresisinvokedwiththeCALLinstruction.Any
inputs(registers)mustbeinitializedbeforethecall;anyoutputs(also
registers)aresetbytheprocedure,andcontaintheappropriatevalueafter
thecall.

Forexample,toprintthe1bytevalue"2F"tothescreen:
moval,2FH
callouthex8;Prints:2F
ToPrint"2AC5"
movax,2AC5H
callouthex16;print2AC5
Toreadanumberfromthekeyboard:
callinhex16;Theaxregisternowcontainsthenumberread

Extern
SincethecodeforthesefunctionsdoesNOTappearinyourASMfile,two
specialstepsmustbetakenincreatingyourexecutablefile.Thefirstisto
declarethenamesoftheproceduresasexternalprocedures.Thisinformsthe
assemblerthatthecodehasbeenwrittenelsewhere,andyoudidn'tjustforget
towriteit.

TheexterndeclarationshouldcomesomeplaceearlyintheASMfile.Although
itdoesn'tmattergreatlywhereitgoes,mostprogrammerswillputthese
declarationsoutsideofallofthesegments.Thetemplatefilegivenhasa
spotforexternals,markedwithacommment.

Theformatforthedeclaration(inthiscase)is:
externprocedure_name:far

A86USERS:TheA86Assemblerusestheolderversionoftheextern
declaration,whichisspelledextrn.Ifyouareusingthea86
assembler(asm86.bat),makesureyouspellthenameoftheinstruction
extrn.

procedure_nameisthenameoftheprocedurethatyouwilluseintheprogram.
Thenameonlyneedstobedeclaredonceinthisway,nomatterhowmanytimes
itisused.ButiftwoormoreDOSIOLTproceduresaretobeused,eachmust
haveaseparatedeclaration.

YoushouldNOTplacetheseexterndeclarationsinyourcodeunlessyouare
actuallyusingtheroutines.Thelinkermayplacethecodefortheprocedure
inyourfinalexecutableevenifitisnevercalled.

LINKING
Aspecialstepmustbetakeninlinking(thesecondhalfofthecompilation
phasedonebyasm86.bat)tolinkthecodeinDOSIOLT.Fortunately,asm86.bat
canhandletheextrafilefairlyautomatically.JustincludetheDOSIOLTon
thecommandline,afteryourasmfilename.

Example:assumingyouhavewrittenaprograminafilecalled"calc.asm"which
containscallstotheDOSIOLTprocedures.Toassembleandlinktheprogram:
A:\>asm86calcdosiolt
Ifyougetan"UndefinedSymbol"error,itisbecauseyoumistyped,or
forgot,theexterndeclarationsfortheDOSIOLTprocedures.Makesure
thesearecorrect.

Ifyougetan"UnresolvedExternal"error,itisbecauseyouforgottoput
"DOSIOLT"asthesecondfilename;i.e.youtyped:asm86calcinsteadof
asm86calcdosiolt.

ThisprogramwillillustratetheuseoftwooftheDOSIOLTprocedures,andalso
theuseofvariables,ratherthanregisters,asplacestostoreinformation.
Theoutlineoftheprogramisasfollows:
Loopforever
Promptfor,andreadanumberintothevariableNUMBER
IFnumber=0,thenbreakoutoftheloop
printNumber,withanappropriateannouncement.
EndLoop

Yourprogramwillneedapromptstring,aresponsestringandawordsized
variableintheDataSegment:

prompt1db0DH,0AH,"Enteranumber:$"
responsedb0DH,0AH,"YouEntered: $"
number dw?

Numberhasbeendeclaredasawordsizedvariable,withnoinitialvalue.The
Codecannowusethename"Number"justlikearegistername(inmostcases).

Thecodefortheprogramis:

number_loop:
;Printthefirstprompt
mov dx,offsetprompt1 mov
ah,09H
int 21H

;ReadanumberintoAXandputitinNUMBER
call inhex16movnumber,ax

;Ifnumber=0theexittheloop
cmpnumber,0H
jeend_number_loop

;PrintThesecondprompt.
mov dx,offsetresponse
mov ah,09H
int 21H
;Printthenumber
mov ax,number
call outhex16
jmp number_loop
end_number_loop:

Notethattheinhex16readsanumberintoAX,andouthex16printsthenumber
AX,yetthiscodewentthroughallthetroubleofstoringthenumberinthe
variable,ratherthanjustleavingitinAXthroughouttheloop.WHY?!?
BecauseAXwasneededinbetweenthereadingandprintingofthecode.Again,
thiskindofjugglingbetweenregistersandvariablesoccursofteninassembly
programming.

SincetwoDOSIOLTproceduresarebeingused,theymustbedeclared.Atthetop
youwillfindtheEXTERNpartofyourprogramtemplate;addtheselinestothe
section:
;===============================Extern======================================
extrninhex16:far
extrnouthex16:far

Thoseareallthechangesneeded.
Don'tforgettoincludetheDOSIOLTfileonthecommandlinewhencompiling,
whichwillbeasm86numloopdosiolt

IdoapologizeforthelengthofthisbutIgottoexcitedwhenIwasmessing
withtheseoldfilesandplayingwiththeseproceduresindosiolt.objfile.

Ifyouwanttotrytousethesefiles,youcanemailmeat
linuxjr@hotmail.com
andrequestthedosiolt.objtousewiththenumloop;Iwillbemorethanhappy
tosendit.

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::...........................................FEATURE.ARTICLE
UsingtheGnuASAssembler
bymammon_

UsingtheGnuASAssembler
mammon_

GASistheGNUprojectportoftheUnixASassembler;itisavailableaspart
ofthebinutilspackagewhichisincludedwithanyoftheGNUcompilers(for
example,GCC).GASsupportisbuiltintothevariousGNUcompilers,andsoGAS
canbeinvokedbyinvokingthecompilerona.S(asmsource)file;howeverit
canalsoberunonanysourcefile(forexample,.asmfiles)byusingthe'as'
command.

TheGASdocumentationisavailableonLinuxinstallationsininfo(.gz)format,
andisviewedusingthecommand'infoas'or'infofas.info'.Forthe
novice,acrashcourseininfo:Infofilesaredesignedinatreestructure,
witheachpageorsectionbeingconsidereda'node';hgetshelp,qquits
info,SPACEscrollsdownthescreen,DELscrollsupthescreen,bjumpstothe
beginningofthenode,ejumpstotheendofthenode,njumpstothenext
node,pjumpstothepreviousnode,gjumpstoaspecifiednode,mjumpstoa
specifiedmenuitem,ssearchestheinfofile,andlstepsback1node.

ThesectionsofthemostinterestinthemanualwillbetheDirectives
('gPseudoOps'),Symbols('gSymbols'),Constants('gConstants'),and
Sections('gSections')nodes.Formoreimmediatereferences,theIntel386
specifictopicscanbeconsulted:'gi386Syntax','gi386Opcodes',
'gi386Regs','gi386prefixes','gi386Memory','gi386jumps'.

TheAT&TSyntax

GASusestheAT&Tsyntax,whichisknowntobeconfusingforthoseusedtothe
Intelassemblersyntax.IthasbeensaidthattheAT&Tsyntaxislessambiguous
thantheIntel,andthusithasitsownappeal.

Registers
OneofthemostobviousdifferencesinsyntaxisthattheregistersintheAT&T
syntaxareprefixedwith%.Thus,'eaxaxalah'wouldbewritten'%eax%ax%al
%ah'forGAS.

OpcodeFormatandOrder
UnliketheIntelsyntaxwhichusestheformat'opcodedest,src',AT&Tsyntax
usestheformat'opcodesrc,dest';thusthecommand'moveax,ebx'inIntel
wouldbe'mov%ebx,%eax'inAT&T.Inaddition,theopcodesinAT&Tsyntaxall
takesuffixestospecifythesizeoftheoperand(notethatthesesuffixescan
beignoredusually,asGASwillguesstheoperandsizebythesizeofthe
registerbeingaccessed)thusonewouldadd'w'toanopcodetospecifya
wordoperand,'b'tospecifyabyteoperand,and'l'tospecifyalongoperand.
TheIntel'mov'opcodewouldthenbespecifiedinAT&Tsyntaxbyusing'movb',
'movw',or'movl'ascircumstanceswarrant.Notethatthiscarriesoverinto
farcalls;asthe'FAR"keywordisnotpresentinGAS,onemustprefix(not
suffix)thecallorjumpwith"l":thusa'farcall'becomes'lcall','far
jmp'becomes'ljmp',and'retfar'becomes'lret'.

ImmediateandAbsolutevalues
Immediatevaluesareprefixedwitha$intheAT&Tsyntax,whileintheIntel
syntaxtheyareunmarked.Thusa'push4'statementbecomesa'push$4'in
AT$T.Also,anabsolutevalueisprefixedbya*,whileinIntelitwouldbe
unmarked.

MemoryReferencing
Thisisthepartthatismostlikelytocausetroubleforthoseusedtothe
Intelsyntax.Intelusesthefollowingsyntaxformemoryreferences:
SECTION:[BASE+INDEX*SCALE+DISP]
whereBASEistheregisterusedasabaseinthereference,INDEXisaregister
usedtocalculateanoffset,SCALEisthemultiplierusedtocalculatethe
offsetfromtheINDEXregister,andDISPisthedisplacementfromtheBASEor
INDEXregister.SomeexamplesfromtheGASmanual:
[ebp4] [BASEDISP] (Note:DISPis4)
[foo+eax*4] [DISP+INDEX*SCALE]
[foo] [DISP] (Valuepointedtoby'foo')
gs:foo SECTION:DISP (Contentsofvariable'foo')
AT&Tsyntaxusesthefollowingsyntaxformemooryreferences:
SECTION:DISP(BASE,INDEX,SCALE)
AswiththeIntelsyntax,alloftheseareoptional(anditappearsthatBASE
andINDEXarerarelyusedtogether).TheGASmanualprovidesthefollowing
examplesequivalenttotheaboveIntelexamples:
4(%ebp) DISP(BASE)
foo(,%eax,4) DISP(,INDEX,SCALE)
foo(,1) DISP(,SCALE) (Note:thesinglecommaisintentional)
%gs:foo SECTION:DISP
Notethatyoumustprovidecommaswithintheparentheseswheneveryouskipan
element(e.g.,ifyoudonotuseBASE).

Toillustrate,herearesomeexamplesofmemoryreferencesmixedinwithasm
opcodes(fromhttp://www.castle.net/~avly/djasm.html):
__AT&T______________________ __Intel_________________________
movl4(%ebp),%eax moveax,[ebp+4])
addl(%eax,%eax,4),%ecx addecx,[eax+eax*4])
movb$4,%fs:(%eax) movfs:eax,4
movl_array(,%eax,4),%eax moveax,[4*eax+array])
movw_array(%ebx,%eax,4),%cx movcx,[ebx+4*eax+array])

Labels&Symbols
LabelsinGASarethesameasinotherassemblers:thenameofthelabel
followedbyacolon.Allsymbolnamesmustbeginwithaletter,aperiod,oran
underscore.Localsymbolsaredefinedusingthedigits09followedbyacolon,
andarereferredtousingthatdigitfollowedbyab(forabackwardreference)
orf(foraforwardreference);notethatthisallowsonly10localsymbols.A
symbolcanbeassignedavalueusingtheequalssign(e.g.'TRUE=1')orby
usingthe.setor.equdirectives.

Directives

GASallowsmostofthestandardassemblerdirectives;whatfollowsarethemost
commonlyused.

.align
Padthesectiontoaspecifiedalignment(e.g.4bytes);thisdirectivetakes
asanargumentthealignmentsized,aswellasanoptionalargumentspecifying
thebyteusedtofillthepadareas(defaultis00).

.ascii,.asciz,.string
Eachofthesedirectivestakesoneormorestringsseparatedbycommas;inthe
.asciidirective,thestringsarenotterminated,inthe.ascizand.string
directivesthestringsarezeroterminated.

.byte,.double,.int,.word
Eachofthesedirectivestakesasanargumentanexpression(forexample,
value1+value2)anddefinesthespecifiednumberofbytes(byte,int,word,
etc)atthecurrentlocationtotheresultoftheexpression.

.data,.section,.text
The.sectiondirectiveallowssegmentsorsectionsofthetargetprogramtobe
definedforthelinker.The.sectiondirectivetakesasectionname,aswellas
sectionflags(b=bss,w=writable,d=data,r=readonly,x=executable
forCOFFfiles;a=allocatable,w=writable,x=executable,@progbits=
data,@nobits=nodataforELFfiles).The.dataand.textdirectivesare
predefined.sectiondirectivesfordataandcodesections.

.equ,.set
Eachofthesesetsthefirstargument(asymbol)withtheresultofthesecond
argument(anexpression),forexample
.equTRUE1
setstheSymbolTRUEtothevalue1.

.extern
ThetraditionalEXTERNdirectiveisavailablebutignored;GAStreatsall
undefinedsymbolsasexterns.

.global,.globl
Thesedirectivesdefineglobal(exported)symbols;eachtakesasanargument
thesymboltobemadeglobal.

.if/.endif
GASprovidestheusualIF...ENDIFdirectivesforconditionalassembly;the.if
directiveisfollowedbyanexpression,andallcodebetweenthe.ifandthe
.endifdirectiveisassembledonlyifthatexpressionreturnsnonzero.

.include
Thisdirectiveincludesafileatthecurrentlocation;ittakesasanargument
thenameofthefileinquotes,forexample
.include"stdio.inc"

AssemblingaProgram

AGASprogramcangeassembledbyinvokingGCCwiththeO2(optimize:level2)
option.NotethatallGASprogramsmusthavea.textsectionandaglobal
"main"label.

Hereisanexampleofa'helloworld'styleprograminGAS:
;gashello.S==========================================================
.text
message:
.ascii"Helloooo,nurse!\0"
.globlmain
main:
pushl$message
callputs
popl%eax
ret
;EOF=================================================================
Thiscanbecompiledwiththecommand
gcc02gashello.Soghello
orwith
asgashello.Sogashello.o
ldogashellogashello.olcsdefsym_start=main
NotethatitismucheasiertouseGCCthantouseAS,asyouwillhaveto
explicitlyspecifythelibrarystolinkto(hencethelcparameter)whenyou
callLD.

TheInt80"pid.asm"programfromlastmonth'sLiuxarticlewouldbewrittenfor
GASasfollows:
;pid.S====================================================================
.globalmain
.text
szText1:
.asciz"GettingCurrentProcessID..."
szDone:
.asciz"Done!"
szError:
.asciz"Errorinint80!"
szOutput:
.string"%d\n"

main:
pushl$szText1
callputs
popl%ecx
mov$20,%eax
int$128
cmp$0,%eax
jeError
pushl%eax
pushl$szOutput
callprintf
popl%ecx
popl%ecx
pushl$szDone
callputs
jmpExit
Error:
pushl$szError
callputs
Exit:
popl%ecx
ret
;EOF====================================================================
Thiscanbecompiledinthesamemannerasthepreviousexample;note,though,
theneedtousedecimalnumberswhencallinginterrupts(the0x??syntaxfor
specifyingahexadecimalintegercausestheopcodetonotberecognizedbythe
assembler).

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::...........................................FEATURE.ARTICLE
AGuidetoNASMforTASMCoders
byGij

Generalities

Thebasicfunctionofanyassemblerittoturnasmintotheequivalentbinary
codefile;that'strueforTASM,NASM,andanyotherassembler.

Thedifferencesariseinthespecialfeatureseachassembleroffersyou.For
example,theMODELdirectiveexistsinTASM,makingiteasierforthecoderto
referencedatavariablesinothersegments.NASMdoesnothaveanequivalent
directive,soyouhavetokeeptrackofthesegmentregistersyourself,andput
segmentoverrideswheretheyareneeded.ThisdoesnotmeanthatNASMdoesn't
havegoodSEGMENTorGROUPsupport;infactithasboth,thoughtheyarenot
quitethesameasinTASM.

It'sadifferentwayofcoding,anditmayseemtorequiremorework,butafter
yougetusedtoitit'seasier,becauseyouknowexactlywhat'sgoingonin
yourcode.NASMactuallygivesyoutheclosestpossibleideaofwhatyourasm
sourcecodewillbecomeonceit'scompiled.

TASMischockfullofdirectives;lookingatasmallreferenceforTASM4.0,
thereareatleastafewdozendirectivesTASMuses,andyouhavetoknow
quiteabitofthembyheart.NASMontheotherhandhasveryfewdirectives.
Actually,youcanwriteanasmfilethatwillassemblejustfinewithoutusing
asingledirective,althoughIdoubtitwillbeusefulinmostcases.

NASMisalsolessambivalenttowardssyntax,whichleaveslessroomfor
softwarebugs,butmakesitmorestrictwhenassembling.IactuallythinkNASM
iseasiertolearnthenTASMsinceit'smuchmorestraightforward.

YourNASMBibleisofcoursetheaccompanyingdocs,youcangetthemina
separatepackagefromthesameplaceyougotthebinariesforNASM.Allinall
IthinkyouwillfindNASMtobejustascapableasTASMifnotmoreso.
Althoughit'smissingsomefeaturesTASMhas,youcanalwaysmailtheauthor
andaskforafeature,andyoujustmightgetluckywhenthenewversioncomesout.

ASMcodeisusuallythesameinanyassembler(AT&Tsyntaxisanexception)
butthereareafewsubtletiesthatTASMcodersshouldlookoutfor.Thedocs
thataccompanyNASMhaveanicelistofthem,andI'llmentionthemost
significantoneshere.

DATAoffsetvsDATAcontents

TASMusesthissyntaxtomove
movesi,offsetMyVar
OR
leaesi,MyVar
LEAisusedtoloadcomplexoffsetslike"[esi*4+ebx]"intoaregister.TASM
supportsLEAevenwhenusedwithasimpleoffsetlike"Myvar".

NASMontheotherhandonlysupportsonewayofloadingasimpleoffsetintoa
register(theLEAformisonlyvalidwhenusingcomplexoffsets):
movesi,MyVar
ThisALWAYSmeansmovetheoffestofMyVarintoesi.

Ontheotherhand,This:
moveax,[MyVar]
WillalwaysmeanmovethecontentsofMyVarintoeax.

However,usingLEAtoloadacomplexoffsetisvalidinbothTASMandNASM:
leaedi,[esi*4+EBX] ;validinbothassemblers

NASMalsosupportaSEGkeyword:
movax,SEGMyVar
Thismovesthesegmentofthevariableintoax.

SegmentOverrides

TASMismorelaxinit'ssyntax,sobothofthesearevalidcode:
movax,ds:[si]
AND
movax,[ds:si]

NASMdoesn'tallowthisifyouspecifyavariableinsidethesquarebrackets
allofthespecifiersshouldbeinsidethesquarebrackets.
Sothisistheonlyvalidoption:
movax,[ds:si]

Specifyingoperandsize

TASMcodersusuallyhavelexicaldifficultieswithNASMbecauseitlacksthe
"ptr"keywordusedextensivelyinTASM.

TASMusesthis:
moval,byteptr[ds:si]
OR
movax,wordptr[ds:si]
OR
moveax,dwordptr[ds:si]

ForNASMThissimplytranslatesinto:
moval,byte[ds:si]
OR
movax,word[ds:si]
OR
moveax,dword[ds:si]

NASMallowsthesesizekeywordsinmanyplaces,andthusgivesyoualotof
controloverthegeneratedopcodesinauniformway.Forexample,thefollowing
areallvalid:
pushdword123
jmp[ds:word1234];thesebothspecifythesizeoftheoffset
jmp[ds:dword1234];fortrickycodewheninterfacing32bitand
;16bitsegments

Itcangetprettyhairywithoperandsizebeingthisfinal,buttheimportant
thingtorememberisyoucanhaveallthecontrolyouneed,whenyouwantit.

Functions

TASMhasspecialdirectivesfordeclaringaprocedureandendingit.Why?
AprocedureisjustanothercodelabelyouCALLinsteadofJMPNASMgotit
right.

TASMuses:
ProcNamePROC
xorax,ax
ret
ProcNameENDP

whileNASMjustuses:
Procname:
xorax,ax
ret

TodeclareaprocedurePUBLIC,justusetheGLOBALdirective:
GLOBALProcname
Procname:
xorax,ax
ret

LocalLabels

ThoseofyouthatknowCalsoknowthatamemberofastructcanbereferenced
asStructInstance.MemberName.ThisisrathersimilartothewayNASMallows
youtouselocallabels.ALocalLabelisdenotedbyprefixingadottothe
labelname:

Label1:
nop
.local:
nop
Label2:
nop
.local:
nop

Thiswon'tgiveyouanerroronmultipledefinitionsoflabel,butyoucan
stilljmptoacertainlabellikethis:
jmpLabel2.local
...soit'slocal,andinawayit'salsoagloballabel.

ORGDirective

NASMsupportstheorgdirective,soifyouarecodingaCOMfileyoucanstart
with:
org0x100h
OR
org100h
(NASMallowsboththeasmandcmethodsofspecifyinghex,sobothofthe
abovearevalid.)

ReservingSpace

Onceagain,hereNASMusesadifferentsyntaxthenthatofTASM.

InTASMyouwoulddeclarea100bytesofuninitializedspacelikethis:
Array1:db100dup(?)

NASMusesitsownkeywordstodothis;theseareRESB,RESWandRESD,
standingforREServeByte,REServeWord,andREServeDword,respectively.
Toreserve10bytes,youwoulduseRES?keywordslikethis:
Array1:RESB100
OR
Array1:RESW100/2
OR
Array1:RESD100/4

DeclaringinitializedspaceismuchlikeTASM,butarraysaredifferent.
InTASM:
Array1:db100dup(1)
InNASM:
Array1:TIMES100db1

TIMESisahandylittledirective,itinstructsNASMtopreformanaction
aspecifiednumberoftimes,intheexampleaboveIpreform"db1"a100
times.TIMEScanbeusedforvirtuallyanything;forexample:
TIMES69nop
willput69nopsatthecurrentpointinthefile.

The$(currentlocation)symbolissupportedbyNASM,andcanbeusedto
specifythe'count'operandtoTIMES,sothisisvalid:
label1:
movax,1
xorax,ax
label2:
TIMES$label1nop
ThisexpandstoTIMES(label2label1),andwillputasmanyonebytenops
afterlabel2,asthebytecountbetweenlabel1andlabel2.

MakingStructs

Ifoughtlongandhardtogetstructsgoing,thedocswereabitvague,and
ittookawhiletogetit,hereitis.

Usingastructisdividedinto2parts,declaringtheprototype,andmakingan
instance.Asimple,2memberstructurewouldbedefinedasfollows:
strucst
stLongresd1
stWordresw1
endstruc

thisdeclaresaprototypestructnamedst,with2members,stLongwhichisa
DWORD,andstWordwhichisaword.Itusesthereservedirectivesbecauseit's
aprototype,notarealstruct.Youcanuseistructomakearealinstancethat
youcanreferenceasdatainyourcode:

mystruc:
istrucst
atstLong,dd1
atstWord,dw1
iend
*Note:it'simportanttoputthelabelonadifferentline.

Thiscreatesastructnamedmystrucoftypest;the"at"keywordisusedto
assigninitialvaluestothemembersofthestruc(i.e.,atthereserverdbytes
ofmemory).

ThenotationforreferencingmembersisnotlikeinC.Thisisbecauseofthe
waystructuresareimplemented;inNASM,eachmemberisassignedanoffset
relativetothebeginningofthestruct:

mystruc:
istrucst
atstLong,dd1;offset0
atstWord,dw1;offset4
iend

Thenotationforreferencingamemberistherefore:
moveax,[mystruc+stLong]

Thisisbecausemystrucisaconstantbase,andthememberisarelativeoffset
toit.It'ssimilartoreferencingadataarray.

OnethingIshouldmention:Ifyoudeclarestructsprototypesasabove,the
membernames/labelswillbeglobal,soyouwillgetcollisionsifyouusethe
samemembernameinyourcodeorinanotherstructprototype.Toavoidthis,
precedethemembernameswithadot'.',andthenreferencetheminrelationto
theprototype'snameintheinstancedeclaration.Forexample:

strucst
.stLongresd1
.stWordresw1
endstruc
mystruc:
istrucst
atst.stLong,dd1
atst.stWord,dw1
iend

Andthisishowyoureferencethemembersincode:
moveax,[mystruc+st.stWord]

Thismayseemconfusing;youshouldunderstandthat"mystruc"isthebaseofa
particularinstance,and"st.stLong"isanoffsetrelativetothestartofthe
struct,soinpseudocodeittranslatesinto:
moveax,[offsetmystruc+(offsetstWordoffsetstart_of_proto]
or
moveax,[offsetmystruc+4]
...whichgivesyouthecorrectoffsetforthestWordmemberofthe"mystruc"
structinstance.

UsingMacros

Thisisalargepartofthenasmdocs,andabittoomuchtogetintoindepth
here.I'lltryandcoverthemajorissues.

Thereare2typesofmacros,onelineandmultiline,allmacrokeywordsare
preceededwitha'%'character.

Anexampleofasinglelinemacro:
%definemul(a,b)(a*b)

...whichwouldbereferenceinthesourcecodeasfollows:
moveax,mul(2,3)

Thiswillbeconvertedinto:
moveax,6

Youcaninvokeothermacrosfromwithinamacro:
%definefancymul(a,b)(a*triple_mul(4))
%definetriple_mul(a)(a*3)
moveax,fancymul(2,3)

Thisbecomes:
moveax,(2*(3*4))

Thesearenotveryusefulexamples,buti'msureyoucanseethepotential.

MultiLinemacrosaremuchthesameassinglelinemacros,butthesyntax
isabitdifferent:
%macronamenumber_of_args
<bodyofmacro>
%endmacro

So,forexample,ifyouwantedtomakeasmallasmeffortsaveryoucouldwrite
thefollowingmacro:
%macroprologue1
pushebp
movebp,esp
subesp,%1
%endmacro
...andthenyoucanuseitinyourcodelikethis:

DemoFunc:
prologue4*2
<bodyoffunction>

Thiswouldsetupastackframeandreserveroomfor2DWORDlocalvariables.
You'llnoticethatargssuppliedtothemacrocanbereferencedas%1....%n,
similartoDOSandUnixshell/batchprogramming.

Thisisjustaquicktaste,there'smoretobelearnedaboutNASMmacros:the
docsareyourfriends.

Includes

Includingfilesiseasy,Ifyouwanttoinclude.inc'sintoyourasmfile
youcanuse:
%include"win32.inc"

Ifyouwishtoincludebinaryfiles,youmustuseadifferentkeyword:
INCBIN "data.bin"

ConditionalAssembly

NASMalsohassupportforconditionalassembly:
%defineINCLUDE_WIN32_INCS
%ifdef INCLUDE_WIN32_INCS
%include"win32.inc"
%include"toolhelp.inc"
%include"messages.inc"
%endif

Thiswayyoucancontroltheinclusionoffilesdefiningonthecommandline:
"nasmwdINCLUDE_WIN32_INC"
orbycommentingoutthe%defineline.Thebodyofthe%ifdefwillbeprocessed
onlyifamacro/definenamedINCLUDE_WIN32_INCSisdefined.

Externs,GlobalsandCommons

WhenCodingamultisourcefilesproject,writingadll,orcallingAPI
functionsyouneedtodeclarevarioussymbols/data/functionsacertaintype
tomakethemavailabletotheAssemblerandyou.

Thereare3typesofsymbolsinNASM:EXTERN,GLOBALandCOMMON.Their
invocationisallthesame:
EXTERNsymbol_name ;usethistodefineAPIcallsforuse
GLOBALsymbol_name
COMMONsymbol_name

Theyallmustappearbeforetheactualsymbolisdefined/referenced.Ifyou
haveexperienceinasm/c,theiruseshouldbeclearEXTERNdeclaresan
externalreferenceofrthelinkertoresolve(an"import"),GLOBALdeclaresa
symboltobeglobally/publiclyavailable(an"export"),andCOMMONdeclaresa
variabletobeofCommondatatype(i.e.,allinstancesofaCOMMONvariable
aremergedintoasingleinstanceduringcompilation).

NASM0.97alsohasIMPORT/EXPORTextensionstothe.objformat,forwriting
DLL's;readthedocsformoreinfo.

SpecifyingSegmentType

YoucandeclaresegmentsmuchthesameasyouwouldinTASM:
segment.datause32CLASS=data
or
segment.textuse32CLASS=code
or
segmentGijuse16CLASS=code

Thisisagoodwaytosetsegmentsstraightforlinking.NotethatNasmdoes
notrequirecertainsegmentstobepresent:youhavefullcontroloverthe
segmentationoftheprogram.

OutputFormats

Nasmsupportsaplethoraofoutputformats;dependingonwhatyouaretrying
toaccomplish,youshouldreadthedocsforspecialextensionstoeachtype.
Theoutputformatischosenusing"nasmftype"onthecommandline,where
typecanbebin,obj,win32andothers.

Eachlinkerlikesdifferentformatstlinklikesobjforexample,while
LCCWIN32likesthewin32format...investigateonyourowntofindthebest
outputformatforyourlinker.

*tip:whenassemblingintothe"obj"type,makesureandusethespecial
"..start:"symboltospecifytheentrypointforthefile.

InClosing

That'sallfornow.Thisisintendedtobea'quickstart'guideforTASM
coderswhowantorneedtomoveintoNASM;itisnotasubstituteforthe
NASMdocumentation.Ifyouneedtoreachme,myemailisgij<at>bigfoot.com
EnjoyNASM!

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::...........................................FEATURE.ARTICLE
TipsonSavingBytesinASMPrograms
byLarryHammick


Theprogrammer'swordforcraftsmanshipis"optimization".Thistermrefersto
conservation,eitherofprogramsizeorexecutiontime.It'stimeincludesnot
justCPUclocks,butthetimeconsumedbyperipherals(e.g.disks,atload
time)andbytheoperatingsystemcalls.Thisarticleisconcernedwiththe
conservationofsize,orbytes.Sizemayrefereithertotheprogramfilesize,
ortothesizeofthememorytheprogramuses.Thetwoarenotalwaysidentical.

Inalltheillustrations,weassumethat16bitcodesegmentsareinvolved.The
syntaxweuseisthatofMASM5.1;thedifferencefromotherassemblersis
slight.

1.Avoiduninitializeddata.

Aninstructionlikethis:
OutputHandledw?
isusuallyawasteofspace.Dependingonthememorymodel(i.e.dependingon
whetherwehaveCS=DS,andthelike),thereareseveralwaystoomitthesetwo
bytesfromtheprogramfileandthememoryimage.

IfDSisthePSPsegment,use:
OutputHandleequwordptrds:[5Ch]
orsimilar,foravalueotherthan5Ch.Anyprogrammaysafelyuseanypartof
thePSPfrom3Chto07Fh,plusthewordat2Ch(environmentsegment).Whenthe
programisfinishedwiththecommandtail(bytes80h0FFh),itcanreusethat
areaaswell.OtherpartsofthePSPshouldnotbemodified,becausetheymay
beneededbyDOSwhentheprogramexits.However,inthecaseofaTSR,the
stayresidentpartofthecode(e.g.aninterrupthandler)mayuseanypartof
thePSPaftertheTSRexithasbeenexecuted.Insuchcases,thePSPmakesa
handybufferof100hbyteswithORG0.

IfDS=CS,youcandefineuninitializedvariableslikethis:
OutputHandledw ?
InputHandledw ?
ORG OutputHandle
Go:movah,30h
int21h
...
movOutputHandle,ax
...
ENDGo

or,equivalently:
OutputHandleequwordptrds:[Go]
InputHandleequwordptrds:[Go+2].

IfDSisadynamicallyallocatedsegment,orifitispartofthestack,there
isthistrick:
OutputHandleequwordptrds:[0]
InputHandleequwordptrds:[2].

Allocatingfileandmemoryspacejustforuninitializedvariableswastesafew
byteshereandthere.Muchworse,forfilesize,istoputwholebuffersand
stacksinthefile:
ReadBuffer db 1000h dup(0)
Stack db 40h dup("Stack!")
Examineafewcommercialprogramsunderahexeditorordebuggertoseehow
commonthispracticeis.Worldwide,thequantityofdiskspacethuswastedmust
beastronomical.Moreover,such"data"getscopiedfromdiskeverytimethe
programisloaded,eventhoughithasnomeaning!Perhapsassemblersand
linkerswillsomedaybesmartenoughtoavoidthis.Fornow,wedohaveEXE
packerssuchasPKLitetocompressblankdatablocks,butthelattercanbe
avoidedentirelyasfollows.

IfDSisadynamicsegmentorpartofthestack:
BufferSize equ1000h
ReadBuffer equ0
WriteBufferequReadBuffer+BufferSize
...
movdx,ReadBuff;ratherthanmovdx,offsetReadBuff
movah,3Fh
int21h
...

Iftheprogramwillbesmallenoughforthecodeandalldatatofitinone
segment,itisdesirabletohaveCS=DS.Thenyoucando:
ReadBuffer equoffsetEndOfCode
WriteBufferequReadBuffer+BufferSize
Go:
... ;codeinstructions
movah,4Ch
int21h;exit
EndOfCodelabelbyte
ENDGo

ThispracticeisnotquitesafeforaCOMprogram,becauseDOSwillloadaCOM
fileintolessthan64Kifnolargerblockisavailableorifmemoryis
fragmented.ForanEXE,theEXEheadercanbeadjustedtopreventtheprogram
fromloadingintotoolittlememory.

2.Putrelateddatatogether.

Anexample:
CursorPositionlabelword
CursorColumndb 0Eh
CursorRow db 8

Youwillbeabletoloadorsavebothvariableswithoneinstruction:
movdx,CursorPosition

Anotherbenefit:
andCursorPosition,0FF00h
jnzNotAtTop

TheANDinstructionsetsonebyteandtestsanother,atthesametime.

3.Avoidforwardreferences.

ForwardreferencesinsourcecanresultinworthlessNOP'sgettingassebled.
Thisisanotherillustrationoftheprinciplethatassemblersareprettydumb.

Consider:
movcx,MsgSize ;(1)
...
Msg db "Hello",0Dh,0Ah
MsgSize equ $offsetMsg

MsgSizeisaconstantword.ButMASMdoen'tknowthatwhenitassemblesthe
instruction(1).Soitprovides3bytesforMsgSize,andlaterfillsinthe
constantwordfollowedbyaNOPbyte.Onesolution:
db 0B9h;opcodeformovcx,immed
dw MsgSize
...
Msgdb "Hello",0Dh,0Ah
MsgSizeequ$offsetMsg

4.Usecheapopcodes.

4.1XCHGAX,Reg16
These8instructionsareeachjust1byte.Don'tuseeitherMOVAX,CXor
MOVCX,AXunlessyouneedthesamevalueinbothregisters.AXisspecialin
thisrespect;instructionssuchasXCHGBX,CXorXCHGSI,DIaretwobytes.
XCHGEAX,Reg32istwobytes(in16bitcodesegments),whereasMOVEAX,ECXetc.
isthree.

4.2CBW,CDW,CDQ
ToputAH=0,theinstructions
xorah,ah
subah,ah
movah,0
occupytwobyteseach.ButifyouknowthatAL>0,theinstructionCBWhasthe
sameeffect(exceptthatitleavestheflagsunchanged)andisonlyonebyte.
Likewise,CWDcansaveoverXORDX,DX.CDQisa2byteopcodebutstillbetter
thanXOREDX,EDX,whichis3bytes.

4.3JCXZ
Thisinstructiondoesnotrequireapreliminaryflagsettinginstruction.So,
youmightprefer
xchgax,cx
jcxzMylabel
to
orax,ax
jzMyLabel,
savingonebyte.BeawarethatJCXZisarelativelyslowopcode.

4.4INCReg16andDECReg16
These16opcodesarejustonebyteeach.TheopcodesINCReg8andDECReg8are
2byte.SouseINCCXinsteadofINCCLifthereisnopossibilityofcarry
fromCLintoCH.IfCXisknowntobe0,INCCXsavesabytevs.MOVCL,1,and
2bytesvs.MOVCX,1.Similartricksapplytogoingfrom1to0,todecrement
ingfrom1to0orfrom0to1.

4.5Prefertheaccumulatortootherregisters.
Thefollowingopcodes,amongothers,arecheaperforAXorEAXthanforother
generalregisters.
MOVreg,mem
MOVmem,reg
ADDreg,mem

5.Beflexibleonflowcontrol.

Blockstructuringisverysensibleinhighlevellanguages,butinASMitis
littlemorethanapedantichabit.InASM,aroutinemayhavemorethanone
entrypointandmorethanoneexit(RETN,RETF,orIRET).Severalroutinesmay
shareexitcodeorentrycode.Aroutineneednotreturnatall.Afewexamples
ofhowthiscansavebytes:

5.1Discardreturnaddressesthatwon'tbeneeded.
Thissortofthingappearsoften:
Mysub:cmpal,3
jaStcRet
...
ret
StcRet:stc
ret

...
callMySub
jcRet1
...
Ret1:ret

Betteris:
Mysub:cmpal,3
jaDontRet
...
ret
DontRet:popax;discardreturnaddressintosomeunneededregister
ret
...
callMySub;returnsonlyifinputisokay
...

5.2Reuseexitcode.
Ifyouseethismorethanonceinyoursource:
popbx
popdx
popax
retn,
makealabelatPOPBX,anduseajumptothatlabelfromeachotheroccurrence.
Ifthishappensmorethanonce:
pushax
pushcx
pushdx
pushbx
considerasubroutine:
SaveRegs:popsi ;storereturnaddressinanunneededregister
pushax
pushcx
pushdx
pushbx
jmpsi

5.3.ConsiderCALLinsteadofJMP.
TheCALLinstructioncanbeusedinsteadofJMPtopassanearaddressat
almostnocost.
movah,30h
int21h
cmpal,5
jaeEnoughDOS
callErrExit
db"ThisprogramrequiresDOS5+",13,10,0
EnoughDOS:
...
ErrExit: popsi;"Returnaddress"actuallypointsatdata.
ErrExitLoop:lodsb
oral,al
jzExit
int29h
jmpshortErrExitLoop
Exit: movax,4CFFh
int21h

Intheaboveexample,theroutineErrExitwritesanASCIIZstringfromCS:SI,
thenexits.

Theoffsetofajumptablecansometimesbepassedinthesameway.
callSmartJump ;doesnotreturn
db 3
dw Handle3;Handle3andHandle7arenearcodeaddresses
db 7
dw Handle7
db 0 ;terminatorforthetable

SmartJump: ;inputisajumptableindexAL.
popdi;"returnaddress"actuallypointsatthejumptable
SmartJumpLoop:cmpbyteptr[di],0
jeNotFound
scasb
jeFound
scasw;cheaperthanincrementingditwice
jmpshortSmartJumpLoop
Found: jmpwordptres:[di]
NotFound:...
TheaboveexampleassumesES=CS.

5.4Shortjumpsarecheaperthannearjumps.
Youcanoftensaveafewbytesbyarrangingyoursourcesothatjumpsareshort
ratherthannear.

Ifthisoccurs:
cmpal,5
jneNot5
jmpCantRun
Not5:
...
jmpCantRun
...
andCantRunisnotreachablebyashortjumpineitherinstance,youmight
stillsaveabytelikeso:
cmpal,5
jneNot5
JmpCantRun:jmpCantRun
Not5:
...
jmpshortJmpCantRun ;2stepjump
...

6.Registersarecheaperthanconstants.

Youshouldneverwritethis(6bytes):
movsi,StringSite ;a16bitconstant
movdi,StringSite

Instead(5bytes):
movsi,StringSite
movdi,si.

Anotherillustration:
MyBytedb11h
...
movMyByte,0 ;a5byteinstruction
movMyByte,bh ;4bytes,andequivalentifbhisknowntobe0
movMyByte,al ;only3bytes.

7.Codecanbeusedasdata.

Herearetwoexamplesofaslicktechniqueknownasselfmodifyingcode.
ErrExit:callWriteMessage
db0B8h;codeforMOVAX,Immed16
ReturnCodedb?,4Ch
int21h ;exitfromprogram

ThelabelErrExitcanbereachedbyJMP'sfromseveralpointsintheprogram.
Beforejumping,thecodepokesinasuitablevalueofReturnCode,dependingon
thetypeoferrorconditionencountered.Theaboveexampleusespartofthe
instructionMOVAX,4Cxxhasavariable,savingbytes.

movax,252Fh ;getINT2FhvectorasES:BX
int21h
movOldInt2F,bx ;thisexampleassumesCS=DSatthispoint
movOldInt2F[2],es
movdx,offsetOurInt2F
movax,252Fh ;setINT2FhvectortoDS:DX
...
OurInt2F:cmpax,1211h ;afunctionthatwewanttocontrol
jneshortJmpOldInt2F
...(handlethisfunction)
iret
JmpOldInt2F:db 0eah ;opcodeforjumptoimmediatefaraddress
OldInt2F dw ?,?
ThismanoeuvresavesbytesversusJMPDWORDPTROldInt2F;again,themethodis
byputtingthevariable(OldInt2F)rightinsidethecode.Devicedriversand
otherTSR'sshouldusethistrick,butIdon'tknowofasingleonewhichdoes
(exceptmyown,naturally).

Safeuseofselfmodifyingcoderequiressomeawarenessofonchipinstruction
caches.It'snogoodtomodifycodeinmemoryifwhatwillgetexecutedis
alreadyontheCPU.Thefollowingtrick,however,isquitesafe.Insteadof:
ErrExit2:moval,2
jmpshortErrExit
ErrExit3:moval,3
jmpshortErrExit
ErrExit5:moval,5
ErrExit:movah,4Ch
int21h

write:
ErrExit2:moval,2
db3Dh ;opcodeforCMPAX,immed,todisablethefollowing
ErrExit3:moval,3 ;2byteinstruction
db3Dh
ErrExit5:moval,5
ErrExit:movah,4Ch
int21h

8.Miscellaneousbytesavers.

Sincetheinstructionsetsofthex86CPU'saresoelaborate,therearemany
moreadhocwaystoreduce,reuse,andrecyclebytes.Thefollowingareonlya
few.

8.1Afteraloop,CXis0.Thus
movcx,1234h
MyLoop:...
...
loopMyLoop
movcx,56h
...
iswasteful.Thelastinstructionshouldbe
movcl,56h.

8.2UseconditionalMOV's.

cmpVideoMode,7
jeBlackAndWhite
movdx,0B800h
jmpshortEither
BlackAndWhite:movdx,0B000h
Either:
...
Theabovecodewastesbytes.Betteris:
movdx,0B800h
cmpVideoMode,7
jneGotVideoBase
movdh,0B0h
GotVideoBase:
...
Theimprovedversionhasonejumpinstructioninsteadoftwo,andinthis
examplesavesanadditionalbytebyresettingonlyDH,notDX.

WiththePentium,Intelintroducedausefulsetofconditionalmov'srightinto
theinstructionset.

8.3Totestthehighbitofaregister,avoidtheconstants80hand8000h.
Forexample,
testdh,80h
jnzMyLabel
is5bytes,but
ordh,dh
jsMyLabel
is4.Thelatterinstructionalsoleavesmoreinformationintheflags.
TESTDH,DHorANDDH,DHhavethesameeffectasORDH,DH.

8.4Todetermineifseveralvariablesofthesamesizeareall0,ORthem
together,andthezeroflagwilltellyou.Todetermineiftheyareall1,
ANDthemtogetherandincrementtheresult.

9.Postlude

IntelmakestheirexcellentCPUdocumentationavailablefree,from:
http://developer.intel.com/design/litcentr/index.htm
ItisinAdobePDFformat;youwillneedtheAcrobatReader,alsofree,from:
http://www.adobe.com/prodindex/acrobat/readstep.html

Ifallelsefails,youcantrytowakemeupat:
hammick@bc.sympatico.ca
RegardsfromVancouver,
Larry

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::................................WIN32.ASSEMBLY.PROGRAMMING
ASimpleWindow
byIczelion

Inthistutorial,wewillbuildaWindowsprogramthatdisplaysafully
functionalwindowonthedesktop.

Downloadtheexamplefilehere.
http://203.148.211.201/iczelion/files/tut03.zip

Preliminary:

WindowsprogramsrelyheavilyonAPIfunctionsfortheirGUI.Thisapproach
benefitsbothusersandprogrammers.Forusers,theydon'thavetolearnhowto
navigatetheGUIofeachnewprograms,theGUIofWindowsprogramsarealike.
Forprogrammers,theGUIcodesarealreadythere,tested,andreadyforuse.The
downsideforprogrammersistheincreasedcomplexityinvolved.Inorderto
createormanipulateanyGUIobjectssuchaswindows,menuoricons,
programmersmustfollowastrictrecipe.Butthatcanbeovercomebymodular
programmingorOOPparadigm.

I'lloutlinethestepsrequiredtocreateawindowonthedesktopbelow:

1.Gettheinstancehandleofyourprogram(required)
2.Getthecommandline(notrequiredunlessyourprogramreceivescommand
line)
3.Registerwindowclass(required,unlessyouusepredefinedwindowtypes,eg.
MessageBox)
4.Createthewindow(required)
5.Showthewindowonthedesktop(requiredunlessyoudon'twanttoshowthe
windowimmediately)
6.Refreshtheclientareaofthewindow
7.Enteraninfiniteloop,checkingformessagefromWindows
8.Ifmessagesarrive,theyareprocessedbyaspecializedfunctionthatis
responsibleforthewindow
9.Quitprogramiftheuserclosesthewindow

Asyoucansee,thestructureofaWindowsprogramisrathercomplexcompared
toaDOSprogram.ButtheworldofWindowsisdrasticallydifferentfromthe
worldofDOS.Windowsprogramsmustbeabletocoexistpeacefullywitheach
other.Theymustfollowstricterrules.You,asaprogrammer,mustalsobemore
strictwithyourprogrammingstyleandhabit.

Content:

Belowisthesourcecodeofoursimplewindowprogram.Beforejumpingintothe
gorydetailsofWin32ASMprogramming,I'llpointoutsomefinepointswhich'll
easeyourprogramming.

YoushouldputallWindowsconstants,structuresandfunctionprototypesinan
includefileandincludeitatthebeginningofyour.asmfile.It'llsaveyou
alotofeffortandavoidtypingerrors.Mostofthetime,youcanuse include
filefromsomeWin32asmexamples.Ihaveusedwindows.incfromSteveGibson's
SmallIsBeautifulexampleandmadesomeadditionsofmyown.

UseIncludeLibdirectivetospecifytheimportlibraryusedinyourprogram.
Forexample,ifyourprogramcallsMessageBoxA,youshouldputtheline:
IncludeLibuser32.lib
atthebeginningofyour.asmfile.ThisdirectivetellsMASMthatyourprogram
willmakeusesoffunctionsinthatimportlibrary.Ifyourprogramcalls
functionsinmorethanonelibrary,justaddanincludelibforeachlibraryyou
use.UsingIncludeLibdirective,youdon'thavetoworryaboutimportlibraries
atlinktime.Youcanusethe/LIBPATHlinkerswitchtotellLinkwhereallthe
libsare.

Whendeclaring APIfunctionprototypes,structures,orconstantsin
yourincludefile,trytosticktotheoriginalnamesusedinWindowsinclude
files,includingcase.Thiswillsaveyoualotofheadachewhenlookingup
someiteminWin32APIreference.

Usemakefiletoautomateyourassemblingprocess.Thiswillsaveyoualotof
typing.

;=============================================================================
includewindows.inc ;.386and.modelarealready
declaredinwindows.inc
includelibuser32.lib ;callstofunctionsin
user32.libandkernel32.lib
includelibkernel32.lib

.DATA ;initializeddata
ClassNamedb"SimpleWinClass",0 ;thenameofourwindowclass
AppNamedb"OurFirstWindow",0 ;thenameofourwindow

.DATA? ;Uninitializeddata
hInstanceHINSTANCE? ;Instancehandleofourprogram
CommandLineLPSTR?

.CODE ;Herebeginsourcode
start:
invokeGetModuleHandle,NULL ;gettheinstancehandleofourprogram.
;UnderWin32,hmodule==hinstance
movhInstance,eax
invokeGetCommandLine ;getthecommandline.
movCommandLine,eax
invokeWinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT;callWinmain
invokeExitProcess,eax ;quitourprogram.Theexitcodeis
;returnedineaxfromWinMain.

WinMainprochInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD
LOCALwc:WNDCLASSEX ;createlocalvariablesonstack
LOCALmsg:MSG
LOCALhwnd:HWND

movwc.cbSize,SIZEOFWNDCLASSEX ;fillvaluesinmembersofwc
movwc.style,CS_HREDRAWorCS_VREDRAW
movwc.lpfnWndProc,OFFSETWndProc
movwc.cbClsExtra,NULL
movwc.cbWndExtra,NULL
pushhInstance
popwc.hInstance
movwc.hbrBackground,COLOR_WINDOW+1
movwc.lpszMenuName,NULL
movwc.lpszClassName,OFFSETClassName
invokeLoadIcon,NULL,IDI_APPLICATION
movwc.hIcon,eax
movwc.hIconSm,0
invokeLoadCursor,NULL,IDC_ARROW
movwc.hCursor,eax
invokeRegisterClassEx,addrwc ;registerourwindowclass

invokeCreateWindowEx,NULL,\
ADDRClassName,\
ADDRAppName,\
WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
NULL,\
NULL,\
hInst,\
NULL
movhwnd,eax
invokeShowWindow,hwnd,CmdShow ;displayourwindowondesktop
invokeUpdateWindow,hwnd ;refreshtheclientarea

.WHILETRUE ;Entermessageloop
invokeGetMessage,ADDRmsg,NULL,0,0
.BREAK.IF(!eax)
invokeTranslateMessage,ADDRmsg
invokeDispatchMessage,ADDRmsg
.ENDW
moveax,msg.wParam ;returnexitcodeineax
ret
WinMainendp

WndProcprochWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
moveax,uMsg ;putthewindowmessageineax
.IFeax==WM_DESTROY ;iftheuserclosesourwindow
invokePostQuitMessage,NULL ;quitourapplication
xoreax,eax
.ELSE ;Defaultmessageprocessing
invokeDefWindowProc,hWnd,uMsg,wParam,lParam
.ENDIF
ret
WndProcendp

endstart

YoumaybetakenabackthatasimpleWindowsprogramrequiressomuchcoding.
Butmostofthesecodesarejust*template*codesthatyoucancopyfromone
sourcecodetoanother.Or,ifyouprefer,youcouldassemblesomeofthese
codesintoalibrarytobeusedasprologueandepiloguecodes.Youcanwrite
onlythecodesinWinMainfunction.Infact,thisiswhatCcompilersdo.They
letyouwriteWinMaincodeswithoutworryingaboutotherhousekeepingchores.
TheonlycatchisthatyoumusthaveafunctionnamedWinMainelseCcompilers
willnotbeabletocombineyourcodeswiththeprologueandepilogue.Youdo
nothavesuchrestrictionwithassemblylanguage.Youcanuseanyfunctionname
insteadofWinMainornofunctionatall.

Prepareyourself.Thisisgoingtobealong,longtutorial.Let'sanalyzethis
programtodeath!

includewindows.inc
includelibuser32.lib
includelibkernel32.lib

Wemustincludewindows.incatthebeginningofthesourcecode.Itcontains
importantAPIfunctionprototypes,structuresandconstantsthatareusedby
ourprogram.Theincludefile,windows.inc,isjustatextfile.Youcanopen
itwithanytexteditor.Thefirsttwolinesare.386and.modeldirectives,so
youdon'thavetospecifythesetwolinesatthebeginningofthesourcecode.

Nextareseveralmacrosthatitsauthor(SteveGibson)frequentlyuses.The
remainingofthefilecontainsimportantstructures,constantsandfunction
prototypes.Pleasenotethatwindows.incdoesnotcontainallstructures,
constants,andfunctionprototypesofWindows.Itjustholdsthemost
frequentlyusedones.Youcanaddinnewitemsiftheyarenotinthefile.

OurprogramcallsAPIfunctionsthatresideinuser32.dll(CreateWindowEx,
RegisterWindowClassEx,forexample)andkernel32.dll(ExitProcess),sowemust
linkourprogramtothosetwoimportlibraries.Thenextquestion:howcanI
knowwhichimportlibraryshouldbelinkedtomyprogram?Theanswer:Youmust
knowwheretheAPIfunctionscalledbyyourprogramreside.Forexample,ifyou
callanAPIfunctioningdi32.dll,youmustlinkwithgdi32.lib.

ThisistheapproachofMASM.TASM'swayofimportlibrarylinkingismuch
moresimpler:justlinktooneandonlyonefile:import32.lib.

.DATA
ClassNamedb"SimpleWinClass",0
AppNamedb"OurFirstWindow",0

.DATA?
hInstanceHINSTANCE?
CommandLineLPSTR?

Nextarethe"DATA"sections.
In.DATA,wedeclaretwozeroterminatedstrings(ASCIIZstrings):ClassName
whichisthenameofourwindowclassandAppNamewhichisthenameofour
window.Notethatthetwovariablesareinitialized.

In.DATA?,threevariablesaredeclared:hInstance(instancehandleofour
program),CommandLine(commandlineofourprogram),andCommandShow(stateof
ourwindowonfirstappearance).Theunfamiliardatatypes,HINSTANCEandLPSTR,
arereallynewnamesforDWORD.Youcanlookthemupinwindows.inc.Notethat
allvariablesin.DATA?sectionarenotinitialized,thatis,theydon'thave
toholdanyspecificvalueonstartup,butwewanttoreservethespacefor
futureuse.

.CODE
start:
invokeGetModuleHandle,NULL
mov hInstance,eax
invokeGetCommandLine
mov CommandLine,eax
invokeWinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
invokeExitProcess,eax
.....
endstart

.CODEcontainsallyourinstructions.Yourcodesmustresidebetween<starting
label>:andend<startinglabel>.Thenameofthelabelisunimportant.Youcan
nameitanythingyoulikesolongasitdoesn'tviolatethenamingconvention
ofMASM.

OurfirstinstructionisthecalltoGetModuleHandletoretrievetheinstance
handleofourprogram.UnderWin32,instancehandleandmodulehandleareone
andthesame.YoucanthinkofinstancehandleastheIDofyourprogram.Itis
usedasparametertoseveralAPIfunctionsourprogrammustcall,soit's
generallyagoodideatoretrieveitatthebeginningofourprogram.

UponreturnfromaWin32function,thefunctionreturnvalue,ifany,canbe
foundineax.Allothervaluesarereturnedthroughvariablespassedinthe
functionparameterlistyoudefinedforthecall.

AWin32functionthatyoucallwillalwayspreservethesegmentregistersand
theebx,edi,esiandebpregisters.Conversely,ecxandedxareconsidered
scratchregistersandarealwaysundefineduponreturnfromaWin32function.
Thebottomlineisthat:whencallinganAPIfunction,expectreturnvaluein
eax.IfanyofyourfunctionwillbecalledbyWindows,youmustalsoplayby
therule:preserveandrestorethevaluesofthesegmentregisters,ebx,edi,
esiandebpuponfunctionreturnelseyourprogramwillcrashveryshortly.

TheGetCommandLinecallisunnecessaryifyourprogramdoesn'tprocessa
commandline.Inthisexample,Ishowyouhowtocallitincaseyouneeditin
yourprogram.

NextistheWinMain()call.Hereitreceivesfourparameters:theinstance
handleofourprogram,theinstancehandleofthepreviousinstanceofour
program,thecommandlineandwindowstateatfirstappearance.UnderWin32,
there'sNOpreviousinstance.Eachprogramisaloneinitsaddressspace,so
thevalueofhPrevInstisalways0.ThisisalefoverfromthedayofWin16.

Note:Youdon'thavetodeclarethefunctionnameasWinMain.Infact,youhave
completefreedominthisregard.Youdon'thavetouseanyWinMainequivalent
functionatall.YoucanpastethecodesinWinMainnexttoGetCommandLineand
yourprogramwillstillbeabletofunctionperfectly.

UponreturnfromWinMain,eaxisfilledwithexitcode.Wepassthatexitcode
asparametertoExitProcesswhichterminatesourapplication.

WinMainprocInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD

TheabovelineisthefunctiondeclarationofWinMain.Notetheparameter:type
pairsthatfollowPROCdirective.TheyareparametersthatWinMainreceives
fromthecaller.Youcanrefertotheseparametersbynameinsteadofbystack
manipulation.Inaddition,MASMwillgeneratetheprologueandepiloguecodes
forthefunction.Sowedon'thavetoconcernourselveswithstackframeon
functionenterandexit.

LOCALwc:WNDCLASSEX
LOCALmsg:MSG
LOCALhwnd:HWND

LOCALdirectiveallocatesmemoryfromthestackforlocalvariablesusedinthe
function.TheLOCALdirectiveisimmediatelyfollowedby<thenameoflocal
variable>:<variabletype>.

SoLOCALwc:WNDCLASSEXtellsMASMtoallocatememoryfromthestackthesizeof
WNDCLASSEXstructureforthevariablenamedwc.Wecanrefertowcinourcodes
withoutanydifficultyinvolvedinstackmanipulation.That'sreallyagodsend,
Ithink.Thedownsideisthatlocalvariablescannotbeusedoutsidethe
functionthey'recreatedandwillbeautomaticallydestroyedwhenthefunction
returnstothecaller.Anotherdrawbackisthatyoucannotinitializelocal
variablesautomaticallybecausethey'rejuststackmemoryallocateddynamically
onfunctionstart.Youhavetomanuallyassignthemwithdesiredvaluesafter
LOCALdirectives.

movwc.cbSize,SIZEOFWNDCLASSEX
movwc.style,CS_HREDRAWorCS_VREDRAW
movwc.lpfnWndProc,OFFSETWndProc
movwc.cbClsExtra,NULL
movwc.cbWndExtra,NULL
pushhInstance
popwc.hInstance
movwc.hbrBackground,COLOR_WINDOW+1
movwc.lpszMenuName,NULL
movwc.lpszClassName,OFFSETClassName
invokeLoadIcon,NULL,IDI_APPLICATION
movwc.hIcon,eax
movwc.hIconSm,0
invokeLoadCursor,NULL,IDC_ARROW
movwc.hCursor,eax
invokeRegisterClassEx,addrwc
;registerourwindowclass

Theinimidatinglinesabovearereallysimpleinconcept.Itjusttakesseveral
linesofinstructiontoaccomplish.Theconceptbehindalltheselinesis
windowclass.Awindowclassisnothingmorethanablueprintorspecification
ofawindow.Itdefinesseveralimportantcharacteristicsofawindowsuchas
itsicon,itscursor,thefunctionresponsibleforit,itscoloretc.You
createawindowfromawindowclass.Thisissomesortofobjectoriented
concept.Ifyouwanttocreatemorethanonewindowwiththesamecharacter
istics,itstandstoreasontostoreallthesecharacteristicsinonlyone
placeandrefertothemwhenneeded.Thisschemewillsavelotsofmemoryby
avoidingduplicationofinformation.

Remember,Windowsisdesignedinthepastwhenmemorychipsareprohibitiveand
mostcomputershave1MBofmemory.Windowsmustbeveryefficientinusingthe
scarcememoryresource.Thepointis:ifyoudefineyourownwindow,youmust
fillthedesiredcharacteristicsofyourwindowinaWNDCLASSorWNDCLASSEX
structureandcallRegisterClassorRegisterClassExbeforeyou'reableto
createyourwindow.Youonlyhavetoregisterthewindowclassonceforeach
windowtypeyouwanttocreateawindowfrom.

WindowshaveseveralpredefinedWindowclasses,suchasbuttonandeditbox.
Forthesewindows(orcontrols),youdon'thavetoregisterawindowclass,
justcallCreateWindowExwiththepredefinedclassname.

ThesinglemostimportantmemberintheWNDCLASSEXislpfnWndProc.lpfnstands
forlongpointertofunction.UnderWin32,there'sno"near"or"far"pointer,
justpointerbecauseofthenewFLATmemorymodel.Butthisisagainalefover
fromthedayofWin16.Eachwindowclassmustbeassociatedwithafunction
calledwindowprocedure.Thewindowprocedureisresponsibleformessage
handlingofallwindowscreatedfromtheassociatedwindowclass.

Windowswillsendmessagestothewindowproceduretonotifyitofimportant
eventsconcerningthewindowsit'sresponsiblefor,suchasuserkeyboardor
mouseinput.It'suptothewindowproceduretorespondintelligentlytoeach
windowmessageitreceives.Youwillspendmostofyourtimewritingevent
handlersinwindowprocedure.

I'lldescribeeachmemberofWNDCLASSEXbelow:

typedefstructtagWNDCLASSEX{
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
HICON hIconSm;
}WNDCLASSEX;

cbSize:ThesizeofWNDCLASSEXstructureinbytes.WecanuseSIZEOFoperator
togetthevalue.

style:Thestyleofwindowscreatedfromthisclass.Youcancombineseveral
stylestogetherusing"or"operator.

lpfnWndProc:Theaddressofthewindowprocedureresponsibleforwindows
createdfromthisclass.

cbClsExtra:Specifiesthenumberofextrabytestoallocatefollowingthe
windowclassstructure.Theoperatingsysteminitializesthebytestozero.

cbWndExtra:Specifiesthenumberofextrabytestoallocatefollowingthewindow
instance.Theoperatingsysteminitializesthebytestozero.Ifanapplication
usestheWNDCLASSstructuretoregisteradialogboxcreatedbyusingtheCLASS
directiveintheresourcefile,itmustsetthismembertoDLGWINDOWEXTRA.

hInstance:Instancehandleofthemodule.

hIcon:Handletotheicon.GetitfromLoadIconcall.

hCursor:Handletothecursor.GetitfromLoadCursorcall.

hbrBackground:Backgroundcolorofwindowscreatedfromtheclass.

lpszMenuName:Defaultmenuhandleforwindowscreatedfromtheclass.

lpszClassName:Thenameofthiswindowclass.

hIconSm:Handletoasmalliconthatisassociatedwiththewindowclass.If
thismemberisNULL,thesystemsearchestheiconresourcespecifiedbythe
hIconmemberforaniconoftheappropriatesizetouseasthesmallicon.
invokeCreateWindowEx,NULL,\
ADDRClassName,\
ADDRAppName,\
WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
NULL,\
NULL,\
hInst,\
NULL

Afterregisteringthewindowclass,wecancallCreateWindowExtocreateour
windowbasedonthesubmittedwindowclass.Noticethatthere're12parameters
tothisfunction.CfunctionprototypeofCreateWindowExisbelow:
HWND
WINAPI
CreateWindowExA(
DWORDdwExStyle,
LPCSTRlpClassName,
LPCSTRlpWindowName,
DWORDdwStyle,
intX,
intY,
intnWidth,
intnHeight,
HWNDhWndParent,
HMENUhMenu,
HINSTANCEhInstance,
LPVOIDlpParam);

Let'sseedetaileddescriptionofeachparameter:
dwExStyle:Extrawindowstyles.Thisisthenewparameterthatisaddedtothe
oldCreateWindow.YoucanputnewwindowstylesforWindows95&NThere.You
canspecifyyourordinarywindowstyleindwStylebutifyouwantsomespecial
stylessuchastopmostwindow,youmustspecifythemhere.YoucanuseNULLif
youdon'twantextrawindowstyles.

lpClassName:(Required).AddressoftheASCIIZstringcontainingthenameof
windowclassyouwanttouseastemplateforthiswindow.TheClasscanbeyour
ownregisteredclassorpredefinedwindowclass.Asstatedabove,everywindow
youcreatedmustbebasedonawindowclass.

lpWindowName:AddressoftheASCIIZstringcontainingthenameofthewindow.
It'llbeshownonthetitlebarofthewindow.IfthisparameterisNULL,the
titlebarofthewindowwillbeblank.

dwStyle:Stylesofthewindow.Youcanspecifytheappearanceofthewindow
here.PassingNULLisokbutthewindowwillhavenosystemmenubox,no
minimizemaximizebuttons,andnoclosewindowbutton.Thewindowwouldnotbe
ofmuchuseatall.YouwillneedtopressAlt+F4tocloseit.Themostcommon
windowstyleisWS_OVERLAPPEDWINDOW.Awindowstyleisonlyabitflag.Thus
youcancombineseveralwindowstylesby"or"operatortoachievethedesired
appearanceofthewindow.WS_OVERLAPPEDWINDOWstyleisactuallyacombination
ofthemostcommonwindowstylesbythismethod.

X,Y:Thecoordinateoftheupperleftcornerofthewindow.Normallythis
valuesshouldbeCW_USEDEFAULT,thatis,youwantWindowstodecideforyou
wheretoputthewindowonthedesktop.

nWidth,nHeight:Thewidthandheightofthewindowinpixels.Youcanalsouse
CW_USEDEFAULTtoletWindowschoosetheappropriatewidthandheightforyou.

hWndParent:Ahandletothewindow'sparentwindow(ifexists).Thisparameter
tellsWindowswhetherthiswindowisachild(subordinate)ofsomeotherwindow
and,ifitis,whichwindowistheparent.Notethatthisisnottheparent
childrelationshipofmultipledocumentinterface(MDI).Childwindowsarenot
boundtotheclientareaoftheparentwindow.Thisrelationshipis
specificallyforWindowsinternaluse.Iftheparentwindowisdestroyed,all
childwindowswillbedestroyedautomatically.It'sreallythatsimple.Since
inourexample,there'sonlyonewindow,wespecifythisparameterasNULL.

hMenu:Ahandletothewindow'smenu.NULLiftheclassmenuistobeused.
LookbackattheamemberofWNDCLASSEXstructure,lpszMenuName.lpszMenuName
specifies*default*menuforthewindowclass.Everywindowcreatedfromthis
windowclasswillhavethesamemenubydefault.Unlessyouspecifyan
*overriding*menuforaspecificwindowviaitshMenuparameter.hMenuis
actuallyadualpurposeparameter.Incasethewindowyouwanttocreate
isofapredefinedwindowtype(ie.control),suchcontrolcannotownamenu.
hMenuisusedasthatcontrol'sIDinstead.WindowscandecidewhetherhMenuis
reallyamenuhandleoracontrolIDbylookingatlpClassNameparameter.If
it'sthenameofapredefinedwindowclass,hMenuisacontrolID.Ifit'snot,
thenit'sahandletothewindow'smenu.

hInstance:Theinstancehandlefortheprogrammodulecreatingthewindow.

lpParam:Optionalpointertoadatastructurepassedtothewindow.Thisis
usedbyMDIwindowtopasstheCLIENTCREATESTRUCTdata.Normally,thisvalueis
settoNULL,meaningthatnodataispassedviaCreateWindow().Thewindowcan
retrievethevalueofthisparameterbythecalltoGetWindowLongfunction.

movhwnd,eax
invokeShowWindow,hwnd,CmdShow
invokeUpdateWindow,hwnd

AftersuccessfulreturnfromCreateWindowEx,thewindowhandleisstoredineax.
Wemustkeepthisvalueforfutureuse.Thewindowwejustcreatedisnot
automaticallydisplayed.YoumustcallShowWindowwiththewindowhandleand
thedesired*displaystate*ofthewindowtomakeitdisplayonthescreen.
NextyoucancallUpdateWindowtoorderyourwindowtorepaintitsclientarea.
Thisfunctionisusefulwhenyouwanttoupdatethecontentoftheclientarea.
Youcanomitthiscallthough.

.WHILETRUE
invokeGetMessage,ADDRmsg,NULL,0,0
.BREAK.IF(!eax)
invokeTranslateMessage,ADDRmsg
invokeDispatchMessage,ADDRmsg
.ENDW

Atthistime,ourwindowisuponthescreen.Butitcannotreceiveinputfrom
theworld.Sowehaveto*inform*itofrelevantevents.Weaccomplishthis
withamessageloop.There'sonlyonemessageloopforeachmodule.This
messageloopcontinuallychecksformessagesfromWindowswithGetMessagecall.
GetMessagepassesapointertoaMSGstructuretoWindows.ThisMSGstructure
willbefilledwithinformationaboutthemessagethatWindowswanttosendto
awindowinthemodule.GetMessagefunctionwillnotreturnuntilthere'sa
messageforawindowinthemodule.Duringthattime,Windowscangivecontrol
tootherprograms.Thisiswhatformsthecooperativemultitaskingschemeof
Win16platform.GetMessagereturnsFALSEifWM_QUITmessageisreceivedwhich,
inthemessageloop,willterminatetheloopandexittheprogram.

TranslateMessageisautilityfunctionthattakesrawkeyboardinputand
generatesanewmessage(WM_CHAR)thatisplacedonthemessagequeue.The
messagewithWM_CHARcontainstheASCIIvalueforthekeypressed,whichis
easiertodealwiththantherawkeyboardscancodes.Youcanomitthiscallif
yourprogramdoesn'tprocesskeystrokes.DispatchMessagesendsthemessagedata
tothewindowprocedureresponsibleforthespecificwindowthemessageisfor.

moveax,msg.wParam
ret
WinMainendp

Ifthemessageloopterminates,theexitcodeisstoredinwParammemberofthe
MSGstructure.YoucanstorethisexitcodeintoeaxtoreturnittoWindows.
Atthepresenttime,Windowsdonotmakeuseofthereturnvalue,butit's
bettertobeonthesafesideandplaysbytherule.

WndProcprochWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

Thisisourwindowprocedure.Youdon'thavetonameitWndProc.Thefirst
parameter,hWnd,isthewindowhandleofthewindowthatthemessageisdestined.
uMsgisthemessage.NotethatuMsgisnotaMSGstructure.It'sjustanumber,
really.Windowsdefinehundredsofmessages,mostofwhichyourprogramswill
notbeinterestedin.Windowswillsendanappropriatemessagetoawindowin
casesomethingrelevanttothatwindowhappens.Thewindowprocedurereceives
themessageandreacttoitintelligently.wParamandlParamarejustextra
parametersforusebysomemessage.Somemessagedoessendaccompanyingdatain
additiontothemessageitself.Thosedataarepassedtothewindowprocedure
bymeansoflParamandwParam.

moveax,uMsg
.IFeax==WM_DESTROY
invokePostQuitMessage,NULL
xoreax,eax
.ELSE
invokeDefWindowProc,hWnd,uMsg,wParam,lParam
.ENDIF
ret
WndProcendp

Herecomesthecrucialpart.Thisiswheremostofyourprogram'sintelligence
resides.ThecodethatrespondstoeachWindowsmessageareinthewindow
procedure.YourcodemustchecktheWindowsmessagetoseeifit'samessage
it'sinterestedin.Ifitis,doanythingyouwanttodoinresponsetothat
messageandthenreturnwithzeroineax.Ifit'snot,youMUSTpassALL
parametersfordefaultprocessingbyDefWindowProc.ThisDefWindowProcisan
APIfunctionthatprocessesthemessagesyourprogramisnotinterestedin.

TheonlymessagethatyouMUSTrespondtoisWM_DESTROY.Thismessageissent
toyourwindowprocedurewheneveryourwindowisclosed.Atthetimeyour
windowprocedurereceivesthismessage,yourwindowisremovedfromthescreen.
Thisisjustanotificationthatyourwindowisnowdestroyed,youshould
prepareyourselftoreturntoWindows.Inresponsetothis,youcanperform
housekeepingpriortoreturntoWindows.Youhavenochoicebuttoquitwhenit
comestothisstate.Ifyouwanttohaveachancetostoptheuserfromclosing
yourwindow,youshouldprocessWM_CLOSEmessage.NowbacktoWM_DESTROY,after
performinghousekeepingchores,youmustcallPostQuitMessagewhichwillpost
WM_QUITbacktoyourmodule.WM_QUITwillmakeGetMessagereturnwithzero
valueineax,whichinturn,terminatesthemessageloopandquitstoWindows.
YoucansendWM_DESTROYmessagetoyourownwindowprocedurebycalling
DestroyWindowfunction.

[ReprintedWithpermissionfromIczelion'sWin32AssemblyHomePage]
http://203.148.211.201/iczelion/index.html

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::................................WIN32.ASSEMBLY.PROGRAMMING
PaintingwithText
byIczelion

Inthistutorial,wewilllearnhowto"paint"textintheclientareaofa
window.We'llalsolearnaboutdevicecontext.

Youcandownloadthesourcecodehere.
http://203.148.211.201/iczelion/files/tut04.zip

Preliminary

TextinWindowsisatypeofGUIobject.Eachcharacteriscomposedof
numerouspixelsthatarelumpedtogetherintoadistinctpattern.That'swhy
it'scalled"painting"insteadof"writing".Normally,youpainttextinyour
ownclientarea(actually,youcanpaintoutsideclientareabutthat'sanother
story).

PuttingtextonscreeninWindowsisdrasticallydifferentfromDOS.InDOS,
youcanthinkofthescreenin80x25dimension.ButinWindows,thescreenare
sharedbyseveralprograms.Somerulesmustbeenforcedtoavoidprograms
writingovereachotherscreendata.Windowsensuresthisbylimitingpainting
areaofeachwindowtoitsownclientareaonly.Thesizeofclientareaofa
windowisnotconstant.Theusercanchangethesizeanytime.Soyoumust
determinethedimensionofclientareadynamically,atruntime.

Beforeyoucanpaintsomethingontheclientarea,youmustaskforpermission
fromWindows.That'sright,youdon'thaveabsolutecontrolofthescreenas
youwereinDOS.YoumustaskWindowsforpermissiontopaintyourownclient
area.Windowswilldeterminethesizeofyourclientarea,font,colorsand
otherGDIattributesandsendahandletodevicecontextbacktoyourprogram.
Youcanthenusethedevicecontextasapassporttopaintingonyourclient
area.

Whatisadevicecontext?It'sjustadatastructuremaintainedinternallyby
Windows.Adevicecontextisassociatedwithaparticulardevice,suchasa
printerorvideodisplay.Foravideodisplay,adevicecontextisusually
associatedwithaparticularwindowonthedisplay.

Someofthevaluesinthedevicecontextaregraphicattributessuchascolors,
fontetc.Thesearedefaultvalueswhichyoucanchangeatwill.Theyexistto
helpreducetheloadfromhavingtospecifytheseattributesineveryGDI
functioncalls.

Whenaprogramneedtopaint,itmustobtainahandletoadevicecontext.
Normally,there'stwowaystoaccomplishthis.
callBeginPaintinresponsetoWM_PAINTmessage.
callGetDCinresponsetoothermessages.

Onethingyoumustremember,afteryou'rethroughwiththedevicecontext
handle,youmustreleaseitduringtheprocessingofasinglemessage.Don't
obtainthehandleinresponsetoonemessageandreleaseitinresponseto
another.

WindowspostsWM_PAINTmessagestoawindowtonotifythatit'snowtimeto
repaintitsclientarea.Windowsdoesnotsavethecontentofclientareaofa
window.Instead,whenasituationoccursthatwarrantsarepaintofclient
area(suchaswhenawindowwascoveredbyanotherandisjustbroughtbackin
front),WindowsputWM_PAINTmessageinthatwindow'smessagequeue.It'sthe
responsibilityofthatwindowtorepaintitsownclientarea.Youmustgather
allinformationabouthowtorepaintyourclientareaintheWM_PAINTsection
ofyourwindowprocedure,sothewindowprocudurecanrepainttheclientarea
whenWM_PAINTmessagearrives.

Anotherconceptyoumustcometotermswithistheinvalidrectangle.Windows
definesaninvalidrectangleasthesmallestrectangularareaintheclient
areathatneedstoberepainted.WhenWindowsdetectsaninvalidrectanglein
theclientareaofawindow,itpostsWM_PAINTmessagetothatwindow.In
responsetoWM_PAINTmessage,thewindowcanobtainapaintstructstructure
whichcontains,amongothers,thecoordinateoftheinvalidrectangle.
YoucallBeginPaintinresponsetoWM_PAINTmessagetovalidatetheinvalid
rectangle.Ifyoudon'tprocessWM_PAINTmessage,attheveryleastyoumust
callDefWindowProcorValidateRecttovalidatetheinvalidrectangleelse
WindowswillrepeatedlysendyouWM_PAINTmessage.

Here'sthestepsyouperforminresponsetoaWM_PAINTmessage:

GetahandletodevicecontextwithBeginPaint.
Painttheclientarea.
ReleasethehandletodevicecontextwithEndPaint

Notethatyoudon'thavetoexplicitlyvalidatetheinvalidrectangle.It's
automaticallydonebytheBeginPaintcall.BetweenBeginPaintEndpaintpair,
youcancallanyGDIfunctionstopaintyourclientarea.Nearlyeveryoneof
themrequiresahandletodevicecontextasaparameter.

Content:

Wewillwriteaprogramthatdisplayatextstring"Win32assemblyisgreat
andeasy!"inthecenteroftheclientarea.

includewindows.inc
includelibuser32.lib
includelibkernel32.lib

.DATA
ClassNamedb"SimpleWinClass",0
AppNamedb"OurFirstWindow",0
OurTextdb"Win32assemblyisgreatandeasy!",0

.DATA?
hInstanceHINSTANCE?
CommandLineLPSTR?

.CODE
start:
invokeGetModuleHandle,NULL
movhInstance,eax
invokeGetCommandLine
invokeWinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
invokeExitProcess,eax

WinMainprochinst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD
LOCALwc:WNDCLASSEX
LOCALmsg:MSG
LOCALhwnd:HWND
movwc.cbSize,SIZEOFWNDCLASSEX
movwc.style,CS_HREDRAWorCS_VREDRAW
movwc.lpfnWndProc,OFFSETWndProc
movwc.cbClsExtra,NULL
movwc.cbWndExtra,NULL
pushhInstance
popwc.hInstance
movwc.hbrBackground,COLOR_WINDOW+1
movwc.lpszMenuName,NULL
movwc.lpszClassName,OFFSETClassName
invokeLoadIcon,NULL,IDI_APPLICATION
movwc.hIcon,eax
movwc.hIconSm,0
invokeLoadCursor,NULL,IDC_ARROW
movwc.hCursor,eax
invokeRegisterClassEx,addrwc
invokeCreateWindowEx,NULL,ADDRClassName,ADDRAppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
hInst,NULL
movhwnd,eax
invokeShowWindow,hwnd,SW_SHOWNORMAL
invokeUpdateWindow,hwnd
.WHILETRUE
invokeGetMessage,ADDRmsg,NULL,0,0
.BREAK.IF(!eax)
invokeTranslateMessage,ADDRmsg
invokeDispatchMessage,ADDRmsg
.ENDW
moveax,msg.wParam
ret
WinMainendp

WndProcprochWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCALhdc:HDC
LOCALps:PAINTSTRUCT
LOCALrect:RECT
moveax,uMsg
.IFeax==WM_DESTROY
invokePostQuitMessage,NULL
.ELSEIFeax==WM_PAINT
invokeBeginPaint,hWnd,ADDRps
movhdc,eax
invokeGetClientRect,hWnd,ADDRrect
invokeDrawText,hdc,ADDROurText,1,ADDRrect,\
DT_SINGLELINEorDT_CENTERorDT_VCENTER
invokeEndPaint,hWnd,ADDRps
.ELSE
invokeDefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xoreax,eax
ret
WndProcendp
endstart

Themajorityofthecodeisthesameastheexampleintutorial3.I'llexplain
onlytheimportantchanges.

LOCALhdc:HDC
LOCALps:PAINTSTRUCT
LOCALrect:RECT

ThesearelocalvariablesthatareusedbyGDIfunctionsinourWM_PAINT
section.hdcisusedtostorethehandletodevicecontextreturnedfrom
BeginPaintcall.psisaPAINTSTRUCTstructure.Normallyyoudon'tusethe
valuesinps.It'spassedtoBeginPaintfunctionandWindowsfillsitwith
appropriatevalues.YouthenpasspstoEndPaintfunctionwhenyoufinish
paintingtheclientarea.rectisaRECTstructuredefinedasfollows:

RECTStruct
left LONG?
top LONG?
right LONG?
bottomLONG?
RECTends

LeftandtoparethecoordinatesoftheupperleftcornerofarectangleRight
andbottomarethecoordinatesofthelowerrightcorner.Onethingtoremember:
Theoriginofthexyaxesisattheupperleftcorneroftheclientarea.So
thepointy=10isBELOWthepointy=0.

invokeBeginPaint,hWnd,ADDRps
movhdc,eax
invokeGetClientRect,hWnd,ADDRrect
invokeDrawText,hdc,ADDROurText,1,ADDRrect,\
DT_SINGLELINEorDT_CENTERorDT_VCENTER
invokeEndPaint,hWnd,ADDRps

InresponsetoWM_PAINTmessage,youcallBeginPaintwithhandletothewindow
youwanttopaintandanuninitializedPAINTSTRUCTstructureasparameters.
Aftersuccessfulcall,eaxcontainsthehandletodevicecontext.Nextyoucall
GetClientRecttoretrievethedimensionoftheclientarea.Thedimensionis
returnedinrectvariablewhichyoupasstoDrawTextasoneofitsparameter.
DrawText'ssyntaxis:

intWINAPIDrawText(HDChdc,
LPCSTRlpString,
intnCount,
LPRECTlpRect,
UNITuFormat);

DrawTextisahighleveltextoutputAPIfunction.Ithandlessomegorydetails
suchaswordwrap,centeringetc.soyoucouldconcentrateonthestringyou
wanttopaint.Itslowlevelbrother,TextOut,willbeexaminedinthenext
tutorial.DrawTextformatsatextstringtofitwithintheboundsofa
rectangle.Itusesthecurrentlyselectedfont,colorandbackground(inthe
devicecontext)todrawthetext.Linesarewrappedtofitwithintheboundsof
therectangle.Itreturnstheheightoftheoutputtextindeviceunits,inour
case,pixels.Let'sseeitsparameters:

hdchandletodevicecontext

lpStringApointertothestringyouwanttodrawintherectangle.
Thestringmustbenullterminatedelseyouwouldhavetospecifyits
lengthinthenextparameter,nCount.

nCountThenumberofcharacterstooutput.Ifthestringisnull
terminated,nCountmustbe1.OtherwisenCountmustcontainthenumberof
charactersinthestringyouwanttodraw.

lpRectApointertotherectangle(astructureoftypeRECT)youwantto
drawthestringin.Notethatthisrectangleisalsoaclippingrectangle,
thatis,youcouldnotdrawthestringoutsidethisrectangle.

uFormatThevaluethatspecifieshowthestringisdisplayedinthe
rectangle.Weusethreevaluescombinedby"or"operator:
DT_SINGLELINEspecifiesasinglelineoftext
DT_CENTERcentersthetexthorizontally.
DT_VCENTERcentersthetextvertically.Mustbeusedwith
DT_SINGLELINE.

Afteryoufinishpaintingtheclientarea,youmustcallEndPaintfunctionto
releasethehandletodevicecontext.

That'sit.Wecansummarizethesalientpointshere:

*YoucallBeginPaintEndPaintpairinresponsetoWM_PAINTmessage.
*Doanythingyoulikewiththeclientareabetweenthecallsto
BeginPaintandEndPaint.
*Ifyouwanttorepaintyourclientareainresponsetoothermessages,
youhavetwochoices:
UseGetDCReleaseDCpairanddoyourpaintingbetweenthesecalls
CallInvalidateRectorUpdateWindowtoinvalidatetheentireclient
area,forcingWindowstoputWM_PAINTmessageinthemessagequeueof
yourwindowanddoyourpaintinginWM_PAINTsection

[ReprintedWithpermissionfromIczelion'sWin32AssemblyHomePage]
http://203.148.211.201/iczelion/index.html

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::........................THE.C.STANDARD.LIBRARY.IN.ASSEMBLY
The_Xprintffunctions
byXbios2

I.INTRODUCTION

ThisisthesecondarticleIwriteontheCstandardlibrary,andperhapssome
ask:"Whyshouldthisinterestus?"or,moregently,"What'sthephilosophy
behindthesearticles?".Well,hereiswhyIwritethesearticles:

ForCprogrammersthatwanttoknowwhathappensbehindtheHLL'curtain'
Forasmprogrammerswhowishtogetideas
ForasmprogrammerswhoneedaCcommandbutwanttokeeptheircode'slim'
(actuallythecodesectionisintendedmoreassourcetocompileandusethan
sourcetoreadandunderstand,that'swhyit'snotalwayswellcommentedin
atutoriallikemanner)
Forme,tobetterunderstandreverseengineeringandassemblycoding.

Ok,nowgoforit....

II.WHATCDOES

Howthevarious_printffunctions(_Xprintf)work:

The_Xprintffunctionscallthe___vprinterfunction,withfourparameters:
1.outputfunctionaddress
2.outputfunctionparameter
3.pointertoformatstring
4.pointertoargumentslist

Parameter1isapointertoafunctionthatoutputstheresultingstring(toa
file,stdoutortomemory).
Parameter2ispassedtothefunctionpointedatbyparameter1,togetherwith
thestringpointeranditslength.
Parameter3is'forwarded'by_Xprintfexactlyasreceivedbytheuser.
Parameter4iseither'forwarded'(bythe_vXprintffunctions)orpointstothe
stack(for'normal'_Xprintffunctions).

FunctionsthatsendoutputtoafileortoSTDOUTalsolock/unlockthestream.
Besidesthat,allthe'dirtyjob'ispassedto___vprinter.

How___vprinterworks:
[thedisassemblyof___vprinterwouldshowthisbetter,butisfartoolarge]

1.Read(next)charfromformatstring
2.IfcharisNUL,finish
3.Ifcharisnota'%',outputitverbatim',loopbackto[1]
4.Ifcharis'%'andnextcharisalso'%',outputasingle'%'andloopto[1]
5.Processthestringuptoa'type_char'
Ifeverythingisok,outputtheresult,loopto[1]
Ifthereisanunknownchar,outputtherestofthestringverbatim,finish

Itisinterestingtonoticehow___vprinterdoesit'soutput:

Alloutputisperformedcharacterbycharacter.Todothis___vprintercallsa
notherroutine(let'scallit_storechar)passingittwoparameters:the
charactertostoreandapointertoan80bytestringinthestackof
___vprinter(actuallyintheCsourcethatmusthavebeenapointertoalocal
structure,because_storecharalsomodifieslocalsafterthose80bytes).
_storecharwritesthecharacterinthestingandifthestringisfilledup,it
callsasecondfunction(callit_writestring)thatcallsthefunctionwhose
pointerwaspassedto___vprinter.Beforereturning,___vprintercalls
_writestringdirectlytooutputwhateverbyteswhereleft._writestringisalso
responsibleforsettingaflagthatwillcause___vprinter(andconsequently
_Xprintf)toreturn1insteadofthenumberofcharsoutput.

Thiswaytoperformoutputhastheadvantageofprintinglongstringswithout
allocatingmuchmemory,whileprintingsmallstringsusingtheoutputfunction
onlyonce.Actuallythisistheonlyadvantageithas.Evenifthissolution
waswrittenwell(whichis_not_),itwouldstillbeawfulin_sprintfand
_vsprintf.In_(v)sprintfcharsarewritteninthelocalbufferfirst,then,
whenthisfillsup,thesecondfunction(_writestring)iscalled,whichcalls
athirdfunction(includedinthesame.OBJfilewith_sprintf)whichfinally
calls_memcpy.Withcarefulrewritingofsprintf,thiscouldbeachievedjust
byasimple,onebyte'stosb'.Thenprintfandfprintfcouldbeimplemented
atopsprintf.Theproblemhereisthatthosefunctionsshould'know'howmuch
bufferspacetoallocate.Maybethesolutiontothiscouldbetoleave
allocatingbufferstotheuser,byjustgivingasprintffunction(actually
Microsoftthoughtthisbeforeme,andtheygiveonlywsprintfandwvsprintf
intheWin32API).

Thisarticlewillactuallyfocusonavsprintffunction,withalltheformat
specifiersinBorlandC(EXCEPTfloatingpointnumbers,whichwould(andmaybe
will)requireaseparatearticle.AlsokeepinmindthatUNIXhasarathermore
complicatedXprintfset,whichI'mgladtoignore:)

III.SOMECOMMENTSONTHECODE

Thisisnotexactly'clear'code.Thisisbecauseitwasnotwrittenfrom
scratch,butistheresultofhandoptimizationappliedtothedisassemblyof
___vprinter(ActuallyBorlandcouldsuemeforthis,butthey'dreallyhavea
hardtimetryingtoshowthatmycoderesemblestheirs:)).Thatis,starting
fromanuncomprehensiblebutworkingsourcecode,Ikeptchangingthesource
codeandcompilinguntilIgotabettersourcecode(yetstilluncomprehensible
:).That'salsoareasonthecodeispoorlycommented.Anywayifyou'rejust
interestedinasimple_sprintffunction,skiptothecodesection.Forthe
curious,herearesomedifferencesmyversionhas:

Aselfcontainedprocedure
Thatis,thereisonlya_sprintffunction,whichcallsnothing,while
_sprintfinvolves:___vprinter,___longtoa,___strlen,plusthreeother
functionscalledby___vprinter(_storechar,_writestringandanotherone
thatconvertspointersintohex)
Muchsmallercode
Muchlessstackused
Probablyfastercode(actuallyitisnotaspeedoptimizedversion,butyet
itmustbemuchfaster)
It'shomemade,andbrandnew:)

IV.THECODE

Well,asIsaid,you'renotexpectedtounderstanditatonce.Yet,ifyou
insist,readandenjoy...

;sprintf.asm============================================================
.386
.modelflat

getarg macroregister
lea eax,[a_argList]
mov edx,[eax]
add dwordptr[eax],4
mov register,[edx]
endm

.data
Null db'(null)',0
align4
jumptable ddoffsetBlankOrPlus ;0
ddoffsetHashSign ;1
ddoffsetAsterisk ;2
ddoffsetMinusSign ;3
ddoffsetDot ;4
ddoffsetDigit ;5
ddoffseth_shortint ;6
ddoffsetd_decimal ;7
ddoffseto_octal ;8
ddoffsetu_unsigned ;9
ddoffsetx_Hexadecimal;10
ddoffsetp_pointer ;11
ddoffsetunknown ;12=f_floating
ddoffsetc_char ;13
ddoffsets_string ;14
ddoffsetn_CharsWritten;15
ddoffsetformatLoop ;16=Ignorecharacter
ddoffsetunknown ;17=Unknownchar
ddoffsetPercent ;18

; !" #$ %& '( )* +, . /


xxlat db0,17,17, 1,17,18,17,17,17,17,2, 0,17, 3,4,17
;0 12 34 56 78 9: ;< => ?
db5, 5,5, 5,5, 5,5, 5,5,17,17,17,17,17,17,17
;@ AB CD EF GH IJ KL MN O
db17,17,17,17,17,12,16,12,8,17,17,17,16,17,16,17
;P QR ST UV WX YZ [\ ]^ _
db17,17,17,17,17,17,17,17,10,17,17,17,17,17,17,17
;` ab cd ef gh ij kl mn o
db17,17,17,13,7,12,12,12,6, 7,17,17,16,17,15, 8
;p qr st uv wx yz {| }~DEL
db11,17,17,14,17, 9,17,17,10,17,17,17,17,17,17,17

.code
_vsprintf procCnearusesebxediesi,a_output:dword,a_format:dword,\
a_argList:dword

localv_width:dword,v_prec:dword,v_zeroLen:dword,\
v_sign:dword,v_strbuf:byte:12,v_strLen:dword

mov esi,[a_format]
mov edi,[a_output]

mainLoop: lodsb ;getcharacter


cmp al,'%' ;testifitis'%'
je shortcontrolChar
stosb ;ifnot,justcopyit
test al,al
jnz shortmainLoop ;ifcharisnotNULL,loop
jmp EndOfString ;jumpifcharisnull
;

controlChar: xor ecx,ecx ;setstageto0


or eax,1
xor ebx,ebx ;noflagsset
mov [v_width],eax ;nowidthgiven
mov [v_zeroLen],ecx ;0
mov [v_prec],eax ;no.precgiven
mov [v_sign],ecx ;0,nosignprefix

formatLoop: xor eax,eax


lodsb
cmp al,''
jl unknown ;charbelow''
movzx edx,byteptrxxlat''[eax]
jmp jumptable[edx*4] ;wejumpwiththecharinAL
;
n_CharsWritten:getarg eax
mov edx,edi
sub edx,[a_output] ;calculatelength

test ebx,16
jnz shortnchars_short

mov [eax],edx
jmp shortfw_mainloop

nchars_short: mov [eax],dx


fw_mainloop: jmp mainLoop
;
Percent: cmp byteptr[esi2],al ;al='%'
jne unknown
stosb
jmp mainLoop
;
;flagcharacters
HashSign: or ebx,1
jmp shortchkflags
MinusSign: or ebx,2
jmp shortchkflags
BlankOrPlus: or byteptr[v_sign],al ;''willbecome'+'
chkflags: or ecx,ecx
jnz unknown
jmp formatLoop
;
Asterisk: getarg eax

cmp ecx,2
jge shortasterisk_prec
test eax,eax
jge shortwidth_positive
neg eax
or ebx,2

width_positive:mov [v_width],eax
mov ecx,3
jmp shortfwwB
;
asterisk_prec: cmp ecx,4
jnz unknown
inc ecx ;setstageto5
mov [v_prec],eax

fwwB: jmp formatLoop


;
Dot: cmp ecx,4
jge unknown
mov ecx,4
inc [v_prec] ;set.precto0
jmp formatLoop
;
Digit: sub al,'0' ;convertASCIItovalue
jnz shortdigit2
or ecx,ecx
jnz shortdigit2
test ebx,2 ;wecomehereifwidth=0n
jnz shortfwwC
or ebx,8
inc ecx ;setstageto1
jmp fwwC
;
digit2: cmp ecx,2
jg shortdigit_prec
mov ecx,2
cmp [v_width],0
jge shortdigit_width
mov [v_width],eax
jmp shortfwwC
;
digit_width: imul edx,[v_width],10
add eax,edx
mov [v_width],eax
jmp shortfwwC
;
digit_prec: cmp ecx,4
jnz unknown
imul edx,[v_prec],10
add eax,edx
mov [v_prec],eax

fwwC: jmp formatLoop


;
h_shortint: or ebx,16
mov ecx,5
jmp formatLoop
;
o_octal: mov ecx,8 ;radix
test ebx,1
jz shortunsigned
mov byteptr[v_sign],'0'
jmp shortinteger

u_unsigned: mov ecx,10 ;radix


unsigned: mov byteptr[v_sign],0 ;nosign
jmp shortinteger

x_Hexadecimal: mov ecx,16 ;radix


mov ah,al
xor al,'X' ;AListhechar('x'or'X')
mov bh,al
test ebx,1
jz shortinteger
mov al,'0'
mov wordptr[v_sign],ax
jmp shortinteger

d_decimal: mov ecx,10 ;radix


or ebx,32

integer: getarg eax


test ebx,16
jz shortinteger_cnvt ;ifnotshort,don'tchange

short_integer: test ebx,32 ;isintegersigned?


jnz shortshort_signed
and eax,0FFFFh ;zeroextend16to32
jmp shortnosign
short_signed: cwde ;signextend16to32

integer_cnvt: test ebx,32


jz nosign
or eax,eax
jns nosign
neg eax
mov byteptr[v_sign],''

nosign: lea edx,[offsetv_strbuf+11]


or eax,eax
jnz shortltoa
cmp [v_prec],eax ;eaxis0ifwearehere
jnz shortzero
mov byteptr[edx],al ;value0with.0prec
mov [v_strLen],eax ;meansnostring
jmp printit ;sooutputnodigits

zero: cmp byteptr[v_sign],'0'


jnz shortltoa
mov byteptr[v_sign],0 ;wedon'twant0x0,nor'00'

;convertEAXintoASCII
ltoa: push edi
push esi
xor esi,esi
mov edi,edx
mov byteptr[edi],0

ltoaLoop: xor edx,edx


div ecx ;ecxistheradix
xchg eax,edx
add al,90h
daa
adc al,40h
daa
or al,bh ;switchcaseifneeded
dec edi
inc esi
mov [edi],al
xchg eax,edx
or eax,eax
jnz shortltoaLoop

mov eax,esi
mov edx,edi
pop esi
pop edi

mov [v_strLen],eax
mov ecx,[v_prec]
or ecx,ecx
js noprec

;Aprecisionwasgiven
sub ecx,eax
jle shortskipzerolen
mov [v_zeroLen],ecx ;ifprec>digitsthen
;add(precdigits)'0'
jmp shortskipzerolen

noprec: test ebx,8


jz shortskipzerolen
cmp [v_width],0
jle shortskipzerolen

;
;wecomehereifwidth=0n
mov ecx,[v_width]
sub ecx,eax ;EAX=[v_strLen]
jle shortskipzerolen
mov eax,dwordptr[v_sign]
or al,al
jz shortsetzerolen
dec ecx
shr eax,8
jz shortsetzerolen
dec ecx
js shortskipzerolen
setzerolen: mov [v_zeroLen],ecx

skipzerolen: mov eax,dwordptr[v_sign]


or al,al
jz shortfinishint
dec [v_width]
shr eax,8
jz shortfinishint
dec [v_width]

finishint: mov eax,[v_zeroLen]


add [v_strLen],eax
jmp printit

;
;Pointer:sameas%.8X

p_pointer: getarg ecx

lea edx,[v_strbuf]
push ebx
mov ebx,7
loopPointer: mov al,cl
shr ecx,4
and al,0Fh
add al,90h
daa
adc al,40h
daa
mov [edx+ebx],al
dec ebx
jns loopPointer
pop ebx

mov byteptr[edx+8],0
mov [v_strLen],8
jmp printit
;
c_char: getarg eax
lea edx,[v_strbuf]
mov [edx],eax ;storeschar(restofEAXis
;notimportant)
mov [v_strLen],1 ;setlengthtoonechar
jmp printit
;
s_string: getarg edx
or eax,1
test edx,edx
jnz shortstrlen_I
mov edx,offsetNull ;Pointer0prints'Null'
strlen_I: inc eax
cmp byteptr[edx+eax],0
jnz shortstrlen_I

cmp eax,[v_prec]
jle shortsetLen
cmp [v_prec],0
jl shortsetLen
mov eax,[v_prec]

setLen: mov [v_strLen],eax

;
;wemustarriveherewithEDXpointingtothestringtoprint
;andit'slengthin[v_strLen]

;leftpadwithspacesIFnecessary
printit: test ebx,2 ;Isitleftjustified?
mov ebx,[v_width]
jnz shortprintPrefix ;ifyes,don'tpadleft
mov ecx,ebx
sub ecx,[v_strLen]
jle printPrefix
mov al,''
repstosb ;>>>leftpad
mov ebx,[v_strLen]

;printoneortwocharsPREFIX
printPrefix: mov eax,[v_sign]
or al,al
jz shortpadZero
stosb ;printthesignprefix
shr eax,8 ;AL=AH,AH=0
jz shortpadZero
stosb ;printthesignprefix

;padwithzeroesIFnecessary
padZero: mov ecx,[v_zeroLen] ;wearesurethatecx>=0
sub [v_strLen],ecx
sub ebx,ecx
mov al,'0' ;ECX=[v_zeroLen]
repstosb ;>>>padwith0s
mov ecx,[v_strLen]
sub ebx,ecx
xchg esi,edx
repmovsb ;>>>copystring
xchg esi,edx
js shortskipRightpad ;referstoSUBEBX,ECX
mov ecx,ebx
mov al,''
repstosb ;>>>rightpadwith''
skipRightpad: jmp mainLoop
;
;
;Ifanunknownspecificationcharacterisfound,_vsprintfentersthe
;followingloop.Thisloopcopiesverbatimalltherestofthestring
;(fromthe'%'on)

unknown: mov al,'%'


scanback: dec esi
cmp [esi],al
jne shortscanback
copyrest: lodsb
stosb
test al,al
jnz shortcopyrest
;
;
;returnthenumberofcharswritten

EndOfString: mov eax,edi


sub eax,[a_output]
dec eax
ret
endp

ends
end
;EOF====================================================================

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::............................................THE.UNIX.WORLD
XWindowsinAssemblyLanguage:PartI
bymammon_

ThesensiblewaytowriteprogramsforXWindowsistouseatoolkitsuchasXt
orGtk;theeasywaywouldbetouseascriptingpackagesuchasPythonor
Tcl/Tk.Modernassemblylanguagecoders,however,areknownforsacrificing
easeandsensibilityinthenameofcuriosityandexecutionspeed;itisin
thisspiritthatthepotentialforprogrammingXWindowsinassemblylanguage
willnowbeinvestigated.

XWindowsProgramming

LikeotherGUIs,XWindowsusesaneventdrivenprogrammingstyleinwhichan
applicationregistersitselfwiththesystem,displaysitsmainuserinterface,
andwaitsforsystemeventssignallingthattheuserhasinteractedwiththe
program.Therearefourmain'levels'ofXWindowsProgramming:XProtocol,
XLib,Xtor'toolkit'programming,andscripting.

XProtocol
XWindowsconsistsoftheXServerwhichhandlesgraphicsoutput,keyboardand
mouseinput,eventsignalling,andcommandssentfromclientprograms(Window
Managers,applications).ClientscommunicatewiththeXServerusingXProtocol,
whichconsistsofbytestreamsexchangedbetweentheclientandtheserver
inasense,likethepacketsthatanetworkclientexchangeswithanetwork
server.XProtocolisvirtuallyuselessforapplicationprogramming,forthe
codingoverheadforeachserverrequestmakesdevelopmentimpractical.The
detailsofXProtocolrequestscanbefoundin'/usr/include/X11/Xproto.h'.

XLib
TheequivalentoftheWin32APIinXWindowsisXLib.Evenifoneusestoolkits
forapplicationcoding,thereisnowaytoescapeXLibcoding.XLibservesas
aninterfacebetweentheclientprogramsandtheXServer;essentially,itisa
libraryofXProtocolfunctionsexportedforusebyapplications.

Xt
Toolkitprogrammingissimilartousingclasslibraries(likeMFC,OWL,orVCL)
ontheWin32platform.Thereareanumberoftoolkitsavailable,suchasQt,
Gtk,XtIntrinsics,Athena,andtheMotiftoolkit.Eachtoolkitconsistsof
extensiblewidgets(likeresourcesinWin32)thatdefinebasicwindowtypes:
buttons,scrollbars,dialogs,editwindows,etc.

Scripting
AwidevarietyofscriptinglanguagesareavailablefortheUnixplatorm,and
manyofthesehavewindowingtoolkitsthatenablethemtoproduceXWindows
applications.ThemostpopularareTcl/Tk,Python,andJava;needlesstosay,
theseprogrammingmethodsmaynotbeimplementedinassemblylanguage.

TheXLibProgrammingModel

AnapplicationwrittenfortheXLibinterfacedemonstratesthebasicprinciples
ofXWindowsprogrammingasawhole.Theseprinciplesmakeupa5stepmethod:

StepI:ConnecttotheDisplay
ThefirststepofanXWindowsapplicationisalsothemostsimple:acallis
madetoXOpenDisplay;theresultreturnedineaxofcourseisapointerto
aDisplaystructure.Thisshouldbesaved,asitwillberequiredforjust
abouteverysubsequentcall:
p_disp=XOpenDisplay(NULL);
Note:IamprovidingthesamplesourceinCforthissection;theassembler
reconstructionwillbepresentedlater.

StepII:InitializeApplicationResources(ColorsandFonts)
Beforeawindowcanbedisplayed,itrequiresaGraphicContext(similartothe
Win32DC);beforetheGCcanbecreated,itrequiresthatthecolorsandfonts
tobeusedbythewindowbeinitialized.

ThesimplestwaytodothisistousetheXLoadQueryFontandtheWhitePixeland
BlackPixelmacros:
mfontstruct=XLoadQueryFont(p_disp,"fixed");
WhitePix=WhitePixel(p_disp,DefaultScreen(p_disp));
BlackPix=BlackPixel(p_disp,DefaultScreen(p_disp));
Onceagain,thevaluesaresavedforlateruse.Notethatamorecomplexmethod
ofallocatingcolorswillbeusedintheassemblycodelater;there,ahandle
tothedefaultXWindowscolormapisobtainedviaacalltoXDefaultColormap,
andXAllocNamedColorisusedtoallocatewhiteandblackpixelvalues:this
accomplishesthesameastheabovecode,butwithoutusingthemacros.

StepIII:CreateWindow(s)
Therearefourthingsthatmustbedonetocreateawindow:thewindowitself
isregisteredwiththeXServerandgivenaResourceID,theGCisregistered
withtheXServerandgivenitsownResourceID,thewindowmustspecifywhich
eventsitwillrespondto,andfinallythewindowmustbemappedintotheX
display.

CreatingthewindowrequiresacalltoXCreateWindoworXCreateSimpleWindow.
XCreateSimpleWindow,usedbelow,requiresthedisplay,parentwindow,xandy
screencoordinates,windowwidthandheight,borderwidth,borderpixelvalue,
andbackgroundpixelvalue.XCreateWindow,usedintheassemblyversion,is
passedthedisplay,parentwindow,x&y,width&height,borderwidth,color
depth,windowclass,visualattribute,valuemask,andanXSetWindowAttributes
structure.Ahandletothecreatedwindowisreturned.
Main=XCreateSimpleWindow(p_disp,DefaultRootWindow(p_disp),100,100,
100,50,1,BlackPix,WhitePix);
CreatingaGCisnotstrictlynecessary;howeverdoingwithoutonecausesthe
applicationappearancetobeunpredicatable(Ifoundthatthebackgroundofmy
windowbecametransparent).AGCiscreatedbycallingXCreateGC,whichis
passedthedisplay,windowhandle,valuemask,andaGraphicsContextValues
structure:
theGC=XCreateGC(p_disp,Main,(GCFont|GCForeground|GCBackground),&gcv);
InputeventsareselectedusingtheXSelectInputfunction,whichispassedthe
display,windowhandle,andtheORedvaluesofeventmasks:
XSelectInput(p_disp,Main,ExposureMask);
Finally,thewindowismappedontothedisplay(andthereforedisplayed)with
theXMapWindowcall,whichisrelativelyselfexplanatory:
XMapWindow(p_disp,Main);

Atthispoint,theproceduremustbecreatedforeachchildwindow(buttons,
scrollbars,etc);thefollowingshowsthecreationofabuttonwithitsownGC,
andselectionoftheExposureandButtonPresseventmasks:
Exit=XCreateSimpleWindow(p_disp,Main,15,1,60,15,1,
WhitePix,BlackPix);
XSelectInput(p_disp,Exit,ExposureMask|ButtonPressMask);
XMapWindow(p_disp,Exit);
exitGC=XCreateGC(p_disp,Exit,(GCFont|GCForeground|GCBackground),&gcv);
NotethataseparateGCisnotneededforeachwindowiftheywillbesharing
thesamebackground,foreground,andfontcolors.

StepIV:EventLoop
Theeventloopisthe'meat'oftheprogram,wheretheapplicationrespondsto
userevents.ThisloopcallsXNextEventtogetthenextsystemevent,and
respondstotheonessenttoitswindows.ThefollowingloopcatchestheExpose
eventanddrawstextintoeachwindowusingXDrawStringontheinitialexposure
ofeachwindow(xexpose.count==0).Inaddition,whentheExitbuttonis
pressed,thewhileloopexitsandtheapplicationterminates.
while(!Done){
XNextEvent(p_disp,&theEvent);
if(theEvent.xany.window==Main){
if(theEvent.type==Expose&&theEvent.xexpose.count==0){
XDrawString(p_disp,Main,theGC,1,40,msgtext,strlen(msgtext));
}}
if(theEvent.xany.window==Exit){
switch(theEvent.type){
caseExpose:
if(theEvent.xexpose.count==0){
XDrawString(p_disp,Exit,exitGC,2,11,extext,strlen(extext));
}
break;
caseButtonPress:
Done=1;}}}

StepV:CleanUpandCloseDisplay
Atthispointtheapplicationisover;thevarioushandlesmustbefreed,the
windowsdestroyed,andthedisplayclosed.Thefunctionstypicallyusedfor
thisaredemonstratedbelow:
XFreeGC(p_disp,theGC);
XFreeGC(p_disp,exitGC);
XUnloadFont(p_disp,mfontstruct>fid);
XDestroyWindow(p_disp,Main);
XCloseDisplay(p_disp);
exit(0);

Notethatsllofthefunctions,structures,andmessagesusedabovearedefined
in'/usr/include/X11/Xlib.h','./X11/Xutil.h'and'./X11/X.h'.

InlineAssemblerWithGCC

DuetothepresenceoftheGASassemblerwithinGCC,inlineassemblerispretty
straightforward.InGCC,the'asm'keywordisusedtoprefixablockofasm
instructions;theformatof'asm'isasfollows:
asm(statements:outputvars:inputvars:modifiedregisters);
Notethatthelastthreeparametersareusuallyusedonlyifyouarewritingan
entirefunctioninassemblylanguage,orifyouaremodifyingregistersthat
youdonotsave(itisbettertosavealltheregistersthatyouwillmodify,
iftheycontainvaluesthatwillbeneededlater).

TheasmstatementsarepasseddirectlytoGAS,andthustheyneedtobeina
formatthatGASwillrecognize.Forthisreason,multilineasmstatementswill
requireanewline(and,optionally,atab)aftereachstatement,likeso:

asm( "
statement1\n
statement2\n
statement3\n
statement4"
:"g"(outvar)
:"g"(invar)
:eax,ebx,ecx
);
or,asIhaveusedbelow:
asm( "statement1\n\t"
"statement2\n\t"
"statement3\n\t"
"statement4\n\t");
Otherthanthattherearenorealrestrictions.Structuresdonotpasswell
betweenCandGAS;ifyouneedtoreferencespecificstructurevariablesfrom
inlineassemblycode,itisbettertoplacethosevariablesintotemporaryC
variables,whcihcanthenbeaccessedfromtheassemblerblockasnormal.The
followingdemonstratesthis:
fid=mfontstruct>fid;
asm("
pushfid\n
pushmainGC\n
pushp_disp\n
callXSetFont\n
add$12,%esp");
MoreinformationontheGCCinlineassemblercanbefoundat:
Avly'sProgrammingPage(http://www.castle.net/~avly/djasm.html)
CodeXSoftware(http://www.gameprog.com/codex/tut/att_asm.html)
Brennan'sDGPPResources(http://brennan.home.ml.org/djgpp/)[CurrentlyDown]

TheXHellSampleProgram

InordertobeabletousetheCheaderfilesforXWindows,thefollowing
programhasbeenwritteninCforGCC,usingCcodeforthedatadeclarations
andassemblerforthe'meat'oftheprogram.InPartIIofthisarticle(next
issue)IwillconvertthisprogramtotheXtmodelandimplementitinNASM.
//xhell.c============================================================
#include<X11/Xlib.h>
#include<X11/Xutil.h>
/*====================GlobalVariableDeclarations=====================*/
char *msgtext="YouareinXHell",
*extext="ExitXHell",
*m_font="fixed",
*app_name="xhello",
*window_title="XHell",
*szWhite="white",
*szBlack="black";
XFontStruct*mfontstruct;
Display*p_disp;
WindowMain,Exit;
GCmainGC,exitGC;
XEventtheEvent;
Fontfid;
Colormapcmap;
intDone=0;
unsignedlongpxBlack,pxWhite;
XSetWindowAttributesxswa;
XColorpixBlack,pixWhite;
XGCValuesgcv;
/*================StartofMainFunction====================*/
main()
{
/*=====ConnecttoDisplay=====*/
asm( "push$0\n\t"
"callXOpenDisplay\n\t"
"movl%eax,p_disp\n\t"
"add$4,%esp\n\t");
/*=====SetupColorsn'Fonts=====*/
asm("pushm_font\n\t"
"pushp_disp\n\t"
"callXLoadQueryFont\n\t"
"add$8,%esp\n\t"
"movl%eax,mfontstruct");
/*=====PrepareMainWindow=====*/
fid=mfontstruct>fid;
/*=====CreateMainGraphicsContext=====*/
//ObtainColormapHandle
asm( "pushp_disp\n\t"
"callXDefaultScreen\n\t"
"add$4,%esp\n\t"
"push%eax\n\t"
"pushp_disp\n\t"
"callXDefaultColormap\n\t"
"add$8,%esp\n\t"
"movl%eax,cmap");
//AllocateWhiteandBlackColors
asm( "push$pixWhite\n\t"
"push$pixWhite\n\t"
"pushszWhite\n\t"
"pushcmap\n\t"
"pushp_disp\n\t"
"callXAllocNamedColor\n\t"
"add$20,%esp");
asm( "push$pixBlack\n\t"
"push$pixBlack\n\t"
"pushszBlack\n\t"
"pushcmap\n\t"
"pushp_disp\n\t"
"callXAllocNamedColor\n\t"
"add$20,%esp");
xswa.background_pixel=pixWhite.pixel;
asm( "push$xswa\n\t"
"movl$1,%ebx\n\t"
"shl$1,%ebx\n\t" //CWBackPixel=1<<1
"push%ebx\n\t"
"push$0\n\t" //CopyFromParent=0(X.h)
"push$1\n\t" //InputOutput=1(X.h)
"push$0\n\t" //CopyFromParent=0(X.h)
"push$1\n\t"
"push$50\n\t"
"push$100\n\t"
"push$100\n\t"
"push$100\n\t"
"pushp_disp\n\t"
"callXDefaultRootWindow\n\t"
"add$4,%esp\n\t"
"push%eax\n\t"
"pushp_disp\n\t"
"callXCreateWindow\n\t"
"add$48,%esp\n\t"
"movl%eax,Main");
gcv.font=fid;
asm("push$gcv\n\t"
"movl$1,%ebx\n\t"
"shl$14,%ebx\n\t" //GCFont=1<<14
"push%ebx\n\t"
"pushMain\n\t"
"pushp_disp\n\t"
"callXCreateGC\n\t"
"add$16,%esp\n\t"
"movl%eax,mainGC");
pxBlack=pixBlack.pixel;
pxWhite=pixWhite.pixel;
asm("pushfid\n\t"
"pushmainGC\n\t"
"pushp_disp\n\t"
"callXSetFont\n\t"
"pushpxBlack\n\t"
"pushmainGC\n\t"
"pushp_disp\n\t"
"callXSetForeground\n\t"
"pushpxWhite\n\t"
"pushmainGC\n\t"
"pushp_disp\n\t"
"callXSetBackground\n\t"
"add$36,%esp");
asm( "movl$1,%ebx\n\t"
"shl$15,%ebx\n\t" //ExposureMask=1<<15
"push%ebx\n\t"
"pushMain\n\t"
"pushp_disp\n\t"
"callXSelectInput\n\t"
"add$12,%esp");
asm("pushMain\n\t"
"pushp_disp\n\t"
"callXMapWindow\n\t"
"add$8,%esp");
/*=====CreateChildWindows=====*/
asm( "pushpxWhite\n\t"
"pushpxBlack\n\t"
"push$1\n\t"
"push$15\n\t"
"push$60\n\t"
"push$1\n\t"
"push$15\n\t"
"pushMain\n\t"
"pushp_disp\n\t"
"callXCreateSimpleWindow\n\t"
"movl%eax,Exit\n\t"
"add$36,%esp");
asm( "movl$1,%ebx\n\t"
"shl$15,%ebx\n\t" //ExposureMask=1<<15
"movl$1,%ecx\n\t"
"shl$2,%ecx\n\t" //ButtonPressMask=1<<2
"or%ecx,%ebx\n\t"
"push%ebx\n\t"
"pushExit\n\t"
"pushp_disp\n\t"
"callXSelectInput\n\t"
"add$12,%esp");
gcv.foreground=pxBlack;
gcv.background=pxWhite;
asm("push$gcv\n\t"
"movl$1,%ebx\n\t"
"shl$14,%ebx\n\t" //GCFont=1<<14
"movl$1,%ecx\n\t"
"shl$2,%ecx\n\t" //GCForeground=1<<2
"or%ecx,%ebx\n\t"
"movl$1,%ecx\n\t"
"shl$3,%ecx\n\t" //GCBackground=1<<3
"or%ecx,%ebx\n\t"
"push%ebx\n\t"
"pushExit\n\t"
"pushp_disp\n\t"
"callXCreateGC\n\t"
"add$16,%esp\n\t"
"movl%eax,exitGC");
asm("pushExit\n\t"
"pushp_disp\n\t"
"callXMapWindow\n\t"
"add$8,%esp");
/*=====EventLoop=====*/
while(!Done){ //ImplementedinCtosavespace;)
XNextEvent(p_disp,&theEvent);
if(theEvent.xany.window==Main){
if(theEvent.type==Expose&&theEvent.xexpose.count==0){
asm( "push$16\n\t"
"pushmsgtext\n\t"
"push$40\n\t"
"push$1\n\t"
"pushmainGC\n\t"
"pushMain\n\t"
"pushp_disp\n\t"
"callXDrawString\n\t"
"add$28,%esp");
}
}
if(theEvent.xany.window==Exit){
switch(theEvent.type){
caseExpose:
if(theEvent.xexpose.count==0){
XDrawString(p_disp,Exit,exitGC,2,11,extext,strlen(extext));
}
break;
caseButtonPress:
Done=1;
}
}
}
/*=====CloseDisplay=====*/
asm( "pushmainGC\n\t"
"pushp_disp\n\t"
"callXFreeGC\n\t"
"add$8,%esp\n\t"
"pushexitGC\n\t"
"pushp_disp\n\t"
"callXFreeGC\n\t"
"add$8,%esp\n\t"
"pushfid\n\t"
"pushp_disp\n\t"
"callXUnloadFont\n\t"
"add$8,%esp\n\t"
"pushMain\n\t"
"pushp_disp\n\t"
"callXDestroyWindow\n\t"
"callXCloseDisplay\n\t"
"add$8,%esp");
}
;EOF=================================================================
Asyoucansee,producinganXLibprograminassemblylanguageisrather
unwieldly.ThecodeproducedisprimarilydatamanipulationsandCcalls;there
isnotalotthatassemblyhastooffer,evenintheeventloop.Infact,the
onlyrealoptimizationasidefromoverheadaddedbythecompiler,whichin
theabovecasewedonotbypassisintheuseofstraightcallsratherthan
themacrosmyoriginalC"helloworld"reliedon.

WhilethisinitselfissomewhatofatriumphforbycodingtheCapplication
inassembleryoulearnexactlyhowmuchsuperfluouscodetherewastogetrid
ofitisnotenough.Inthenextissue,IwillcoverXtprogrammingin
assembler,whichwillusewidgets/resourcesratherthancreatewindowsfrom
scratch,thereforeplacingthebulkofthecodeinexistingsystemlibraries
andthereforemakingtheresultantapplicationmuchsmaller.

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::................................ASSEMBLY.LANGUAGE.SNIPPETS
IsASCII?
byTroyBenoist

;Summary:RoutinetotestwhethervalueinAHisASCIIornot(0127d=ASCII)
;Compatibility:AllDOSversions
;Notes:4BYTES!Input:AH=valuetocheck.
cmpah,80 ;8DFC80ComparevalueinAHto128andsetflags.
salc ;D6SetAL=FFifCF=1,orsetAL=0ifCF=0.
;REGISTERSDESTROYED:ALRETURNS:AL=0ifAHisnotASCII,FFisso.

ENUM
bymammon_
;Summary:ANASMmacroemulatingtheC'ENUM"command
;Assembler:NASM
%macroENUM2*;Usage:ENUMintSYMBOLS
%assigni%1 ;whereintisthenumbertobeginenumerationat[0]
%rep%0 ;SYMBOLSisalistofSymbolstodefine
%2EQU0xi ;Example:ENUM0TRUEFALSE
%assignii+1;thisEQUatesTRUEto0andFALSEto1
%rotate1 ;Example:ENUM11JACKQUEENKING
%endrep ;thisEQUsJACKto11,QUEENto12,KINGto13
%endmacro

CallTable
bymammon_
;Summary:ErrorHandlertodemonstratecalltables
;Compatibility:
;Notes:TheEQUsdefineoffsetsfromthestartofErrorHandler.Thus,
; ERROR_FILE_NOT_FOUNDisatoffset0,ERROR_FILE_READ_ONLYis
; atoffset4(onedwordfromoffset0),etc.
; Eachentryinthecalltablecontainstheaddressofthe
; codelabellistedthere...so,inorder,ErrorHandlercontains
; theaddressesforthefunctionsERROR1,ERROR2,ERROR3,and
; ERROR4.
; Thecodetocallanerrorhandlerusesasitsbase
; call[Errorhandler]
; or,callthefunctionwhoseaddressisstoredatlocation
; ErrorHandler.ByaddingtheEQUstothisbase,onegetsthe
; offsetforeachfunctionwithinErrorHandler.
ERROR_FILE_NOT_FOUND EQU 0
ERROR_FILE_READ_ONLY EQU 4
ERROR_DISK_FULL EQU 8
ERROR_UNKNOWN EQU 12

ErrorHandler:
; HereliestheCallTable
DWORDERROR1
DWORDERROR2
DWORDERROR3
DWORDERROR4
; HereendstheCallTable

;Handlersforvariouserrors;offsetstothesearestoredintheCallTable
ERROR1:
...CodetoCreateFile...
ret
ERROR2:
...CodetoCHMODFile...
ret
ERROR3:
...CodetoDisplayDiskFullMessage...
jmpExit_Program
ERROR4:
...CodetoDisplayUnknownSystemErrorCode...
jmpExit_Program

;CodetocallVariouserrors
calldwordptr[ErrorHandler+ERROR_FILE_NOT_FOUND]
calldwordptr[ErrorHandler+ERROR_FILE_READ_ONLY]
jmpdwordptr[ErrorHandler+ERROR_FILE_DISK_FULL]
jmpdwordptr[ErrorHandler+ERROR_FILE_UNKNOWN]

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::...........................................ISSUE.CHALLENGE
PEProgramDisplaysItsCommandLine
byXbios2

TheChallenge

WritethesmallestpossiblePEprogram(win32)thatoutputsit'scommandline.

TheSolution

Thisproblemlooksliketheoneaboutthe11byte.COMprogramsolvedonthe
previousissue.Yetthemethodusedtosolveitisentirelydifferent.Thisis
becausewhile.COMfilesincludejustrawcodeanddata,thePEfilesincludea
headerwithinformationonthefile.Itisthisheaderthatmustbe'tweaked'
togetasmallfile.

Beforegoingon,somethingsmustbecleared:

1.Thisarticlerelies_heavily_on"ThePEFileFormat"byB.Luevelsmeyer
(whomIreallythank).Youareadvisedtofindthe.txtandreadit.Ofcourse
Microsoftprovidesit'sowndocumentationbuttheywouldhardlyeversay'this
seemstobeignored'fortheirownformat.

2.IfyouthinkthatPE(PortableExexutable)istheformatintroducedbywin95
you'rewrong.NotonlywasPEcreatedforwinNT,butitalsoseemsthatwin95
isnot100%PEcompatible.Anyway,thisarticlehasbeenwrittenforwinNT,and
Idon'tthinkanythingwillruninwindows95.

3.Thisarticlewasbasedona'trialanderror'method.Somesolutionsexist
onlybecausetheywork.Sodon'taskwhy...(Actuallythetrialanderror
resultedintwoBSODs,thusprovingthataprogramcancrashwindowsNTwithout
evenrunningit'sowncode)

4.No,I'mnotparanoid.Ijustlikepushingthingstotheirlimit:)

Now,ontothesolution...

Thecodetoprintthecommandlinelookslikethis:
normal.asm
.386
.modelflat

extrnGetCommandLineA:proc
extrnGetStdHandle:proc
extrnWriteFile:proc

.data?
dummy db?

.code
start:
call GetCommandLineA
xor ecx,ecx
push ecx
loop1: inc ecx
cmp byteptr[eax+ecx],0
jne shortloop1
push esp
push ecx
push eax
push 11
call GetStdHandle
push eax
call WriteFile
ret
ends
endstart

somecommentsonthecode:
the.data?sectionispresentbecauseIcan'tmakeTASMworkwithoutanydata
thereisnoExitProcess.Init'splacethereisasimple'ret'.Thisis
becausetheentrypointisactuallycalledbykernel32withthefollowingpiece
ofcode:

call [ebp+8] ;[ebp+8]holdstheentrypointaddress


push eax
jmp label:
...
label: call ExitThread

ThisprogramcompilesunderTASMto4KBlong.Those4096bytesaredivided
likethis:

DosStub 256
PEHeader 248
4sectionheaders160
padding 872

code 50
padding 462
imports 132
padding 380
reloc 16
padding 1520

Thismeansthatwehave:
16%header
5%code/data
79%padding

ItseemsthatTASMcan'tcreateanythingsmaller.So,thecodewillhavetobe
writtenbyhandinahexeditor.Actuallyyoudon'thavetoworry,asyou'll
onlyhavetowrite192bytesforthefinalprogram(believeitornot!).

Inordertoshrinkthefile,thefollowingstepsmustbetaken:RemovePadding,
UseaSingleSection,RemovetheDOSStub,TweakthePEHeader,Squeezethe
Code,SqueezetheImports,and'ReAssemble'theProgram.

1.Removepadding

Bychangingthe'FileAlignment'fieldinthePEheader,allthepaddingcanbe
discarded.(Actuallyitseemsthatwin95won'tallowthis)

2.Useonesection

TASMcreatesthefollowingsections:

.code :code
.data :initializedanduninitializeddata
.idata :imports
.reloc :relocationinfo

The.relocsectionisnotneeded,asonlyDLLsgetrelocated
The.datasectionisonlypresentbecauseIcan'thaveTASMcreateanormal
executablewithoutadatasection.
The.idatasectioncanthenbemergedwiththe.codesection.Rememberthatthe
nameofeachsectiondoesnotdependonwhatthesectioncontains,sincetheOS
findsthingslikeimports,relocationsorresourcesfromthedirectoryinthe
PEheader.

3.NoDOSstub

AllcompilersthatcompilePEexecutablescreateaDOSstubthatdisplaysa
messagelike'ThisprogrammustberununderWin32'.YetthisisNOTrequired
bythePEformat.WhatPEneeds(asseenin[ntdll.dll]RtlImageNtHeaderor
[imagehlp.dll]ImageNtHeader)is:

PIECEI:DOSHEADER

0000|4D5A****************************
0010|********************************
0020|********************************
0030|************************????????

where????istheoffsetofthePEheaderfromthebeginningofthefile

4.TweakedPEheader

ThePEheaderconsistsofthefollowingstructures:

IMAGE_NT_SIGNATURE:00004550h
IMAGE_FILE_HEADER:
WORDMachine ;>>014ChforIntel386
WORDNumberOfSections ;1forthisexample
DWORDTimeDateStamp ;*
DWORDPointerToSymbolTable ;*
DWORDNumberOfSymbols ;*
WORDSizeOfOptionalHeader ;>>70h(Opt.header+directories)
WORDCharacteristics ;>>0102hfor32bitexecutable
IMAGE_OPTIONAL_HEADER:
WORDMagic ;0B01h
BYTEMajorLinkerVersion ;*
BYTEMinorLinkerVersion ;*
DWORDSizeOfCode ;*
DWORDSizeOfInitializedData ;*
DWORDSizeOfUninitializedData ;*
DWORDAddressOfEntryPoint ;>>????RVAofentrypoint
DWORDBaseOfCode ;*
DWORDBaseOfData ;*
DWORDImageBase ;>>00100000hforthisexample
DWORDSectionAlignment ;2
DWORDFileAlignment ;2
WORDMajorOperatingSystemVersion;*
WORDMinorOperatingSystemVersion;*
WORDMajorImageVersion ;*
WORDMinorImageVersion ;*
WORDMajorSubsystemVersion ;>>0004
WORDMinorSubsystemVersion ;>>0000
DWORDWin32VersionValue ;*
DWORDSizeOfImage ;>>????
DWORDSizeOfHeaders ;*
DWORDCheckSum ;*
WORDSubsystem ;0003forwin32consoleapplication
WORDDllCharacteristics ;*
DWORDSizeOfStackReserve ;00100000h
DWORDSizeOfStackCommit ;00001000h
DWORDSizeOfHeapReserve ;00100000h
DWORDSizeOfHeapCommit ;00001000h
DWORDLoaderFlags ;*
DWORDNumberOfRvaAndSizes ;2datadirectories(Exports&Imports)
...anumber(actually2)ofthefollowing:
IMAGE_DATA_DIRECTORY:
DWORDVirtualAddress ;0forexports,????forimports
DWORDSize ;0forexports,????forimports
...anumber(actually1)ofthefollowing:
IMAGE_SECTION_HEADER:
BYTEName[8] ;*(Anythingwelike)
DWORDVirtualSize ;?!(h.o.wordmustbezero??)
DWORDVirtualAddress ;>>????
DWORDSizeOfRawData ;>>????
DWORDPointerToRawData ;>>????
DWORDPointerToRelocations ;*
DWORDPointerToLinenumbers ;*
WORDNumberOfRelocations ;*
WORDNumberOfLinenumbers ;*
DWORDCharacteristics ;*

SotherawhexdataforthePEheaderare:
PIECEII:PEHEADER

|504500004C010100****************
|********700002010B01************
|****************????????********
|********000010000200000002000000
|****************04000000********
|????????****************0300****
|00001000001000000000100000100000
|********020000000000000000000000
|????????????????****************
|********????????????????????????
|********************************

NOTES:
????meansthatthevalueisneededbuthastobefilledinlaterasit
dependsonthecode
****meansthatthevalueiseithercompletelyignoredoritcanbesetto
anyvaluewithoutraisinganerror
themaindifferencebetweenthisanda'normal'PEheaderisthatthesizeof
theoptionalheaderis70h(112bytes)insteadofthestandard0E0h(224bytes).
Thisisbecausethereareonly2directoriesinsteadof16.Thisseemstobe
theminimumnumberofdirectoriespossible,asthereseemstobenowayof
runningan.exethathasnoimports.

5.Squeezedcode

Eventhoughthecodewehaveisalreadytight,ithasonemajordrawback:It
invokesthreeAPIfunctions.Torealizewhatthismeansjustthinkthatthe
namesofthefunctionsareincludedintheimportssectionasnormalASCII
whichmeansthatonlythenameswouldtake36bytes...

Thesolutionhere(sincethosefunctionsareneeded)istocallthefunctions
directly.Thisispossiblebecausekernel32.dllisneverrelocatedsothe
functionentrypointsarealwaysthesame(foragivenversionofwindows).

ForNT4thosevaluesare:
GetStdHandle:77F01CBB
WriteFile:77F0D354

GetCommandLineisaspecialcasesinceithastheformat:
GetCommandLineAprocnear
mov eax,[77F4657Ch]
retn
GetCommandLineAendp

sothefinalcodewilllooklike:
code.hex
A17C65F477 mov eax,offsetCommandLine
BEBB1CF077 mov esi,offsetGetStdHandle
33C9 xor ecx,ecx
51 pushecx
41 incecx
803C0800 cmp [eax+ecx],0
75F9 jnz 07
54 pushesp
51 pushecx
50 pusheax
6AF5 push11;StdOut
FFD6 callesi;GetStdHandle
50 pusheax
B854D3F077 mov eax,offsetWriteFile
FFD0 call eax
C3 ret

6.Squeezedimports

[Comment:readatextonPEformattobetterunderstandwhat'sgoingon]
Asmentionedearlier,thePEfilemusthaveanimportsdirectoryinorderto
loadproperly.Yet,sincewecallAPIfunctionsdirectly,weonlyhaveto
specifyonedummyimport.Agoodchoice(sinceitreallyhasashortname)is
'Arc'from'gdi32.dll'.Tospecifythisimportedfunctionweshouldneed:

IMAGE_IMPORT_DESCRIPTORforgdi32.dll:
OriginalFirstThunk ;*
TimeDateStamp ;*
ForwarderChain ;*
Name ;>>????RVAofASCIIstring'gdi32.dll',0
FirstThunk ;>>????RVAdescribedlater...
IMAGE_IMPORT_DESCRIPTORfullofzeroestospecifyendofimports
OriginalFirstThunk ;*
TimeDateStamp ;*
ForwarderChain ;*
Name ;0Thisischeckedtoseeifitistheend...
FirstThunk ;*

'FirstThunk'istheRVAofa0terminatedlistofRVAs,oneforeachfunction
inthespecifiedDLL.ForthisexampleweonlyneedoneRVAfollowedbyanull
dword.ThisRVAwillpointtoastructureIMAGE_IMPORT_BY_NAME:
WORDHint ;*
BYTEName[...] ;'Arc',0

Byputtingallthistogetherwewouldhave:

PIECEIII:IMPORTS

|************************dword1
|dword2dword300000000********
|00000000********

dwords1and2arethetwoRVAsfortheIMAGE_IMPORT_DESCRIPTOR.dword3isthe
RVAtotheIMAGE_IMPORT_BY_NAME.So,dword2istheRVAofdword3.Wealso
needspaceforthetwostrings'gdi32.dll',0and'Arc',0.

Thereisawaytouseevenlessbytesfortheimports.Justrememberthatthe
importsareexaminedafterthefilehasbeenmappedintomemory.So,since
memoryisallocatedinblocks,aftertheendofthefiletherewillbeaspace
fullofzeroes.Sobyplacingthethreedwordsinthelast12bytesofthefile,
thereisnoneedforthetwozeroes.

7.'Assemble'theprogram

Thevaluesmarkedas????willbe:
OffsetofPEheader :00000010
AddressOfEntryPoint :00000002
SizeOfImage :000000C0
ImportsRVA :000000A8
ImportsSize :00000028
SectionVirtualAddress :00000000
SectionSizeOfRawData :000000C0
SectionPointerToRawData:00000000
DllNameRVA :00000098
DllFirstThunkRVA :000000BC
DllFunctionHint/Name :000000AE

NoticethattheSectiondataandtheHeader(DOSandPE)arethesamething.
ThesectionRVAis0,sofileoffsetandRVAsarethesame.Thecodewillbe
brokeninthreepieces,connectedbytwojumps.Thefinalresultwillbe:

THEPROGRAM

0000|4D5AA17C65F477BEBB1CF07733C9EB08
0010|504500004C0101005141803C080075F9
0020|5451EB06700002010B01506AF5FFD650
0030|B854D3F077FFD0C30200000010000000
0040| 000010000200000002000000
0050| 04000000
0060|C0000000 0300
0070|00001000001000000000100000100000
0080| 020000000000000000000000
0090|A80000002800000067646933322E646C
00A0|6C00000000000000C000000000000000
00B0|4172630098000000BC000000AE000000

Blankbytesaremeaningless,andcanbesettoanyvalue.

WrappingUp

Well,ifyoumanagedtoreaduptohere,andunderstoodwhathappened,Iguess
youneednomoreexplanations.Ijustgaveanidea(actuallyMANYideas).Maybe
onanotherarticleIwillstartexploringthepossibilitiesthis'experiment'
showedme...

NextIssueChallenge

WritearoutineforconvertingASCIIhextobinaryin6bytes.

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::.......................................................FIN

TopNextIssue

S-ar putea să vă placă și