Sie sind auf Seite 1von 24

::/\::::::.

:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.Oct/Nov98
:::\_____\::::::::::.Issue1
::::::::::::::::::::::.........................................................

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

TABLEOFCONTENTS

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

"VGAProgramminginMode13h".............................LordLucifer

"SMCTechniques:TheBasics"...................................mammon_

"GoingRing0inWindows9x".....................................Halvar

Column:Win32AssemblyProgramming
"TheBasics"..............................................Iczelion
"MessageBox"..............................................Iczelion

Column:TheCstandardlibraryinAssembly
"_itoa,_ltoaand_ultoa"...................................Xbios2

Column:TheUnixWorld
"x86ASMProgrammingforLinux"............................mammon_

Column:IssueSolution
"11byteSolution"..........................................Xbios2

+++++++++++++++++++++++IssueChallenge++++++++++++++++++++
Writeaprogramthatdisplaysitscommandlinein11bytes

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

WelcometothefirstissueofAssemblyProgrammingJournal.Assemblylanguage
hasbecomeofrenewedinteresttoalotofprogrammers,inwhatmustbea
backlashtothesurgeofpoorqualityRADdevelopedprograms(fromDelphi,VB,
etc)releasedasfree/sharewareoverthepastfewyears.Assemblylanguage
codeistight,fast,andoftenwellcodedyoutendtofindfewer
inexperiencedcoderswritinginassemblylanguagethanyoudowritingin,say,
VisualBasic.

Theselectionofarticlesissomewhateclecticandshoulddemonstratethe
focusofthismagazine:i.e.,ittargetstheassemblylanguageprogramming
community,notanyparticulartypeofcodingsuchasWin32,virus,ordemo
programmimg.Asthemagazineisnewlybornandmuchofitspurposemayseem
unclear,IwilldevotetherestofthiscolumntothemostcommonquestionsI
havereceivedviaemailregardingthemag.

Howoftenwillanissuebereleased?

Barringhazard,anissuewillbereleasedeveryothermonth.

Whattypesofarticleswillbeaccepted?

Anythingtodowithassemblylanguage.Obviouslyrepeatsofpreviously
presentedmaterialarenotnecessaryunlesstheyenhanceorclarifythe
earliermaterial.ThefocuswillbeonIntelx86instructionsets;however
codingforotherprocessorsisacceptable(thoughoutofcourtesyitwouldbe
goodpointtoanx86emulatorfortheprocessoryouwriteon).

PersonallyIamlookingforarticlesontheareasofasemblylanguagethat
interestme:codeoptimization,demo/graphicsprogramming,viruscoding,unix
andotherOSasmcoding,andOSinternals.

Demos(withsource)andqualityASCIIart(forissuecovers,columnlogos,
etc)areespeciallywelcome.

Forwhatlevelofcodingexperienceisthemagintended?

Themagazineisintendedtoappealtoasmcodersofalllevels.Eachissue
willcontainmostlybeginnerandintermediatelevelcode/techniques,asthese
willbynaturebeofthegreatestdemand;howeveroneofthegoalsofAPJis
toincludeenoughadvancedmaterialtomakethemagazineappealto"pros"as
well.

Howwillthemagbedistributed?

AssemblyProgrammingJournalhasitsownwebpageat
http://asmjournal.freeservers.com
whichwillcontainthecurrentissueandanarchiveofpreviousissues.The
pagealsocontainsaguestbookandadisucssionboardforarticlewritersand
readers.

Anemailsubscriptionmaybeobtainedbysendinganemailto
asmjournal@mailcity.com
withthesubject"SUBSCRIBE";startingwiththenextissue,Assembly
ProgrammingJournalwillbeemailedtotheaddressyousentthemailfrom.

Wrapup

That'sthebulkofthe"faq".Enjoythemag!

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::...........................................FEATURE.ARTICLE
VGAProgramminginMode13h
byLordLucifer

ThisarticlewilldescribehowtoprogramVGAgraphicsMode13husingassembly
language.Mode13histhe320x200x256graphicsmode,andisfastandvery
convenientfromaprogrammer'sperspective.

ThevideobufferbeginsataddressA000:0000andendsataddressA000:F9FF.
Thismeansthebufferis64000byteslongandthateachpixelinmode13his
representedbyonebyte.

Itiseasytosetupmode13handthevideobufferinassemblylanguage:

mov ax,0013h ;Int10VideoBIOSServices


int 10h ;ah=00SetVideoMode
;al=13Mode13h(320x200x256)

mov ax,0A000h ;pointsegmentregisterestoA000h


mov es,ax ;wecannowaccessthevideobufferas
;offsetsfromregisteres

Attheendofyourprogram,youwillprobablywanttorestorethetextmode.
Here'show:

mov ax,0003h ;Int10VideoBIOSServices


int 10h ;ah=00SetVideoMode
;al=03Mode03h(80x25x16text)

Accessingaspecificpixelintthebufferisalsoveryeasy:

;bx=xcoordinate
;ax=ycoordinate
mul 320 ;multiplyycoordby320togetrow
add ax,bx ;addthiswiththexcoordtogetoffset

mov cx,es:[ax] ;nowpixelx,ycanbeaccessedases:[ax]

Hmm...Thatwaseasy,butthatmultiplicationisslowandweshouldgetridof
it.That'seasytodotoo,simplybyusingbitshiftinginsteadofmultiplica
tion.Shiftinganumbertotheleftisthesameasmultiplyingby2.Wewantto
multiplyby320,whichisnotamultipleof2,but320=256+64,and256and
64arebothevenmultiplesof2.Soafasterwaytoaccessapixelis:

;bx=xcoordinate
;ax=ycoordinate
mov cx,bx ;copybxtocx,tosaveittemporatily
shl cx,8 ;shiftleftby8,whichisthesameas
;multiplyingby2^8=256
shl bx,6 ;nowshiftleftby6,whichisthesameas
;multiplyingby2^6=64
add bx,cx ;nowaddthosetwotogether,whisis
;effectivelymultiplyingby320
add ax,bx ;finallyaddthexcoordtothisvalue
mov cx,es:[ax] ;nowpixelx,ycanbeaccessedases:[ax]

Well,thecodeisalittlebitlongerandlooksmorecomplicated,butIcan
guaranteeit'smuchfaster.

Toplotcolors,weuseacolorlookuptable.Thislookuptableisa768
(3x256)array. Eachindexofthetableisreallytheoffsetindex*3.The3
bytesateachindexholdthecorrespondingvalues(063)ofthered,green,
andbluecomponents.Thisgivesatotalof262144totalpossiblecolors.
However,sincethetableisonly256elementsbig,only256differentcolors
arepossibleatagiventime.

ChangingthecolorpaletteisaccomplishedthroughtheuseoftheI/Oportsof
theVGAcard:

Port03C7histhePaletteRegisterReadport.
Port03C8histhePaletteRegisterWriteport
Port03C9histhePaletteDataport

Hereishowtochangethecolorpalette:

;ax=paletteindex
;bl=redcomponent(063)
;cl=greencomponent(063)
;dl=bluecomponent(063)

mov dx,03C8h ;03c8h=PaletteRegisterWriteport


out dx,ax ;chooseindex

mov dx,03C9h ;03c8h=PaletteDataport


out dx,al
mov bl,al ;setredvalue
out dx,al
mov cl,al ;setgreenvalue
out dx,al
mov dl,al ;setbluevalue

Thatsallthereistoit.Readingthecolorpaletteissimilar:

;ax=paletteindex
;bl=redcomponent(063)
;cl=greencomponent(063)
;dl=bluecomponent(063)

mov dx,03C7h ;03c7h=PaletteRegisterReadport


out dx,ax ;chooseindex

mov dx,03C9h ;03c8h=PaletteDataport


in al,dx
mov bl,al ;getredvalue
in al,dx
mov cl,al ;getgreenvalue
in al,dx
mov dl,al ;getbluevalue

Nowallweneedtoknowishowtoplotapixelofacertaincoloratacertain
location.Itsveryeasy,givenwhatwealreadyknow:

;bx=xcoordinate
;ax=ycoordinate
;dx=color(0255)
mov cx,bx ;copybxtocx,tosaveittemporatily
shl cx,8 ;shiftleftby8,whichisthesameas
;multiplyingby2^8=256
shl bx,6 ;nowshiftleftby6,whichisthesameas
;multiplyingby2^6=64
add bx,cx ;nowaddthosetwotogether,whisis
;effectivelymultiplyingby320
add ax,bx ;finallyaddthexcoordtothisvalue
mov es:[ax],dx ;copycolordxintomemorylocation
;thatsallthereistoit

Ok,wenowknowhowtosetupMode13h,setupthevideobuffer,plotapixel,
andeditthecolorpalette.

Mynextarticlewillgoontoshowhowtodrawlines,utilizethevertical
retraceforsmootherrendering,andanythingelseIcanfigureoutbythat
time...

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::...........................................FEATURE.ARTICLE
SMCTechniques:TheBasics
bymammon_

Oneofthebenefitsofcodinginassemblylanguageisthatyouhavetheoption
tobeastrickyasyoulike:thebinarygymnasticsofviralcodedemonstrate
thisaboveallelse.Oneoftheviral"tricks"thathasmadeitswayinto
standardprotectionschemesisSMC:selfmodifyingcode.

InthisarticleIwillnotbediscussingpolymorphicvirusesormutation
engines;Iwillnotgointoanyspecificsoftwareprotectionscheme,orcover
anyantidebugger/antidisassemblertricks,oreventouchonthematterofthe
PIQ.Thisisintendedtobeasimpleprimeronselfmodifyingcode,forthose
newtotheconceptand/orimplementation.

Episode1:OpcodeAlteration

Oneofthepurestformsofselfmodifyingcodeistochangethevalueofan
instructionbeforeitisexecuted...sometimesastheresultofacomparison,
andsometimestohidethecodefrompryingeyes.Thistechniqueessentially
hasthefollowingpattern:
movreg1,codetowrite
mov[addrtowriteto],reg1
where'reg1'wouldbeanyregister,andwhere'[addrtowriteto]'wouldbea
pointertotheaddresstobechanged.Notethat'codetowritewouldideally
beaninstructioninhexadecimalformat,butbyplacingthecodeelsewherein
theprograminanuncalledsubroutine,orinadifferentsegmentitis
possibletosimplytransferthecompiledcodefromonelocationtoanothervia
indirectaddressing,asfollows:
callchanger
movdx,offset[string];thiswillbeperformedbutignored
label: movah,09 ;thiswillneverbeperfomed
int21h ;thiswillexittheprogram
....
changer:movdi,offsetto_write;loadaddressofcodetowriteinDI
movbyteptr[label],[di];writecodetolocation'label:'
ret ;returnfromcall
to_write:movah,4Ch ;terminatetoDOSfunction

thissmallroutinewillcausetheprogramtoexit,thoughinadisassemblerit
atfirstappearstobeasimpleprintstringroutine.Notethatbycombining
indirectaddressingwithloops,entiresubroutinesevenprogramscanbe
overwritten,andthecodetobewrittenwhichmaybestoredintheprogramas
datacanbeencryptedwithasimpleXORtodisguiseitfromadisassembler.

Thefollowingisacompleteasmprogramtodemonstratepatching"live"code;
itaskstheuserforapassword,thenchangesthestringtobeprinted
dependingonwhetherornotthepasswordiscorrect:
;smc1.asm==================================================================
.286
.modelsmall
.stack200h
.DATA
;bufferforKeyboardInput,formattedforeasyreference:
MaxKbLengthdb05h
KbLengthdb00h
KbBufferdd00h

;strings:notethepasswordisnotencrypted,thoughitshouldbe...
szGuessIt db 'Caretoguessthesupersecretpassword?',0Dh,0Ah,'$'
szString1 db 'Congratulations!Yousolvedit!',0Dh,0Ah,'$'
szString2 db 'Ah,damn,toobadeh?',0Dh,0Ah,'$'
secret_word db "this"

.CODE
;===========================================
start:
mov ax,@data ;setsegmentregisters
mov ds,ax ;sameas"assume"directive
mov es,ax
callQuery ;promptuserforpassword
mov ah,0Ah ;DOS'GetKeyboardInput'function
mov dx,offsetMaxKbLength ;startofbuffer
int 21h
callCompare ;comparepasswordsandpatch
exit:
movah,4ch ;'TerminatetoDOS'function
int21h
;===========================================
Query proc
movdx,offsetszGuessIt ;Promptstring
movah,09h ;'DisplayString'function
int21h
ret
Query endp
;===========================================
Reply proc
PatchSpot:
movdx,offsetszString2 ;'Youfailed'string
movah,09h ;'DisplayString'function
int21h
ret
Reply endp
;===========================================
Compare proc
mov cx,4 ;#ofbytesinpassword
mov si,offsetKbBuffer ;startofpasswordinputinBuffer
mov di,offsetsecret_word ;locationofrealpassword
repcmpsb ;comparethem
orcx,cx ;aretheyequal?
jnz bad_guess ;nope,donotpatch
movwordptrcs:PatchSpot[1],offsetszString1 ;patchtoGoodString
bad_guess:
callReply ;outputstringtodisplayresult
ret
Compare endp
end start
;EOF=======================================================================

Episode2:Encryption

EncryptionisundoubtedlythemostcommonformofSMCcodeusedtoday.Itis
usedbypackersandexeencryptorstoeithercompressorhidecode,byviruses
todisguisetheircontents,byprotectionschemestohidedata.Thebasic
formatofencryptionSMCwouldbe:
movreg1,addrtowriteto
movreg2,[reg1]
manipulatereg2
mov[reg1],reg2
where'reg1'wouldbearegistercontainingtheaddress(offset)ofthe
locationtowriteto,andreg2wouldbeatemporaryregisterwhichloadsthe
contentsofthefirstandthenmodifiesthemviamathematical(ROL)orlogical
(XOR)operations.Theaddresstobepatchedisstoredinreg1,itscontents
modifiedwithinreg2,andthenwrittenbacktotheoriginallocationstill
storedinreg1.

Theprogramgivenintheprecedingsectioncanbemodifiedsothatit
unencryptsthepasswordbyoverwritingit(sothatitremainsunencrypted
untiltheprogramisterminated)byfirstchangingthe'secret_word'valueas
follows:
secret_word db 06Ch,04Dh,082h,0D0h

andthenbychangingthe'Compare'routinetopatchthe'secret_word'location
inthedatasegment:
;===========================================
magic_key db 18h,25h,0EBh,0A3h;notverysecure!

Compare proc;Step1:Unencryptpassword
mov al,[magic_key] ;putbyte1ofXORmaskinal
mov bl,[secret_word] ;putbyte1ofpasswordinbl
xor al,bl
mov byteptrsecret_word,al;patchbyte1ofpassword
mov al,[magic_key+1] ;putbyte2ofXORmaskinal
mov bl,[secret_word+1] ;putbyte2ofpasswordinbl
xor al,bl
mov byteptrsecret_word[1],al;patchbyte2ofpassword
mov al,[magic_key+2] ;putbyte3ofXORmaskinal
mov bl,[secret_word+2] ;putbyte3ofpasswordinbl
xor al,bl
mov byteptrsecret_word[2],al;patchbyte3ofpassword
mov al,[magic_key+3] ;putbyte4ofXORmaskinal
mov bl,[secret_word+3] ;putbyte4ofpasswordinbl
xor al,bl
mov byteptrsecret_word[3],al;patchbyte4ofpassword
mov cx,4 ;Step2:ComparePasswords...nochangesfromhere
mov si,offsetKbBuffer
mov di,offsetsecret_word
rep cmpsb
or cx,cx
jnz bad_guess
mov wordptrcs:PatchSpot[1],offsetszString1
bad_guess:
callReply
ret
Compare endp

Notetheadditionofthe'magic_key'locationwhichcontainstheXORmaskfor
thepassword.Thiswholethingcouldhavebeenmademoresophisticatedwitha
loop,butwithonlyfourbytestheabovespeedsdebuggingtime(and,thereby,
articlewritingtime).Notehowthepasswordisloaded,XORed,andrewritten
onebyteatatime;using32bitcode,thewhole(dword)passwordcouldbe
written,XORedandanrewrittenatonce.

Episode3.Foolingwiththestack

ThisisatrickIlearnedwhiledecompilingsomeofSunTzu'scode.What
happenshereisprettyinteresting:thestackismovedintothecodesegment
oftheprogram,suchthatthetopofthestackissettothefirstaddressto
bepatched(which,BTW,shouldbetheoneclosesttotheendoftheprogram
duetothewaythestackworks);thebyteatthisaddressisthePOPedintoa
register,manipulated,andPUSHedbacktoitsoriginallocation.Thestack
pointer(SP)isthendecrementedsothatthenextaddresstobepatched(i
bytelowerinmemory)isnowatthetopofthestack.

Inaddition,thebytesarebeingXORedwithaportionoftheprogram'sown
code,whichdisguisessomewhattheactualvalueoftheXORmask.Inthe
followingcode,IchosetousethebytesfromStart:(200hwhencompiled)
uptobutnotincludingExit:(214hwhencompiled;Exit1=213h).
However,aswithSunTzu'soriginalcodeIkeptthe"reverse"sequenceofthe
XORmasksuchthatbyte213histhefirstbyteoftheXORmask,andbyte200h
isthelast.AftersomeexperimentationIfoundthiswastheeasiestwayto
syncapatchprogramorahexeditortothestackmanipulativecode;since
thestackmovesbackwards(aforwardmovingstackismoretroublethanitis
worth),usinga"reverse"XORmaskallowsbothfilepointersinapatchertobe
INCedorDECedinsync.

Whyisthisanissue?Unliketheprevioustwoexamples,thefollowingdoesnot
containtheencryptedversionofthecodetobepatched.Itsimplycontains
thesourcecodewhich,whencompiled,resultsintheunencryptedbyteswhich
arethenrunthroughtheXORroutine,encrypted,andthenexecuted(which,if
youhavefollowedthusfar,willimmediatelydemonstratetobenogood...
thoughitisafantasticwayofcrashingtheDOSVM!).

Oncetheprogramiscompiledyoumusteitherpatchthebytestobedecrypted
manually,orwriteapatchertodothejobforyou.Theformerismore
expedient,thelatterismorecertainandisamustifyouplanonmaintaining
thecode.InthefollowingexampleIhaveembedded2CCh's(Int3)inthecode
attheforeandaftendofthebytestobedecryptedsection;apatcherneed
simplysearchforthese,countthebytesinbetween,andthenXORwiththe
bytesbetween200213h.

Onceagain,thissampleisacontinuationofthepreviousexample.Init,I
havewrittenaroutinetodecrypttheentire'Compare'routineoftheprevious
sectionbyXORingitwiththebytesbetween'Start'and'Exit'.Thisis
accomplishedbyseetingthestacksegmentequaltothecodesegment,then
settingthestackpointerequaltotheend(highest)addressofthecodetobe
modified.AbyteisPOPedfromthestack(i.e.it'soriginallocation),XORed,
andPUSHedbacktoitsoriginallocation.Thenextbyteisloadedby
decrementingthestackpointer.Onceallofthecodeitdecrypted,controlis
returnedtothenewlydecrypted'Compare'routineandnormalexecution
resumes.

;===========================================
magic_key db 18h,25h,0EBh,0A3h

Compare proc
movcx,offsetEndPatch[1];startaddrtowriteto+1
subcx,offsetpatch_pwd;endaddrtowriteto
movax,cs
movdx,ss ;savestacksegmentimportant!
movss,ax ;setstacksegmenttocodesegment
movbx,sp ;savestackpointer
movsp,offsetEndPatch;startaddrtowriteto
movsi,offsetExit1 ;startsddrofXORmask
XorLoop:
popax ;getbytetopatchintoAL
xoral,[si] ;XORalwithXorMask
pushax ;writebytetopatchbacktomemory
decsp ;loadnextbytetopatch
decsi ;loadnextbyteofXORmask
cmpsi,offsetStart ;endsddrofXORmask
jaeGoLoop ;ifnotatendofmask,keepgoing
movsi,offsetExit1 ;startXORmaskover
GoLoop:
loopXorLoop ;XORnextbyte
movsp,bx ;restorestackpointer
movss,dx ;restorestacksegment
jmp patch_pwd
db 0CCh,0CCh ;Identifcationmark:START
patch_pwd: ;nochangesfromhere
mov al,[magic_key]
mov bl,[secret_word]
xor al,bl
mov byteptrsecret_word,al
mov al,[magic_key+1]
mov bl,[secret_word+1]
xor al,bl
mov byteptrsecret_word[1],al
mov al,[magic_key+2]
mov bl,[secret_word+2]
xor al,bl
mov byteptrsecret_word[2],al
mov al,[magic_key+3]
mov bl,[secret_word+3]
xor al,bl
mov byteptrsecret_word[3],al
;comparepassword
mov cx,4
mov si,offsetKbBuffer
mov di,offsetsecret_word
repcmpsb
orcx,cx
jnz bad_guess
movwordptrcs:PatchSpot[1],offsetszString1
bad_guess:
callReply
ret
Compare endp
EndPatch:
db0CCh,0CCh ;IdentificationMark:END

Thiskindofprogramisveryhardtodebug.Fortesting,Isubstituted'xor
al,[si]'firstwith'xoral,00h',whichwouldcausenoencryptionandis
usefulfortestingcodeforfinalbugs,andthenwith'xoral,EBh',which
allowedmetoverifythatthecorrectbyteswerebeingencrypted(itnever
hurtstocheck,afterall).

Episode4:Summation

Thatshoulddemonstratethebasicsofselfmodifyingcode.Thereareafew
techniquestoconsidertomakedevelopmenteasier,thoughreallyanySMC
programswillbetricky.

Themostimportantthingistogetyourprogramrunningcompletelybeforeyou
startoverwritinganyofitscodesegments.Next,alwayscreateaprogramthat
performsthereverseofanydecryption/encryptioncodenotonlydoesthis
speedupcomilationandtestingbyautomatingtheencryptionofcodeareas
thatwillbedecryptedatruntime,italsoprovidesagoodtoolforerror
checkingusingadisassembler(i.e.encryptthecode,disassemble,decryptthe
code,disassemble,compare).Infact,itisagoodideatoencapsulatetheSMC
portionofyourprograminaseparateexecutableandtestitonthecompiled
"releaseproduct"untilallofthebugsareoutofthedecryptionroutine,and
onlythenaddthedecryptionroutinetoyourfinalcode.TheCCh'landmarks'
(codemarks?)areextremelyusefulaswell.

Finally,doyourdebuggingwithdebug.comforDOSapplicationsthedebugger
isquick,small,andifitcrashesyousimplyloseaWindowsDOSbox.The
abilitytoviewtheprogramaddressspaceaftertheprogramhasterminatedbut
beforeitisunloadedisanotherdistinctadvantage.

MorecomplexexamplesofSMCprogramscanbefoundinDarkAngel'scode,the
Rhinceengine,orinanyofthepermutationenginesusedinploymorphic
viruses.AcknowledgementsgotoSunTzuforthestacktechniqueusedinhis
ghfcrackmeprogram.

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::...........................................FEATURE.ARTICLE
GoingRing0inWindows9x
byHalvarFlake

ThisarticlegivesashortoverviewovertwowaystogoRing0inWindows9xin
anundocumentedway,exploitingthefactthatnoneoftheimportantsystem
tablesinWin9xareonpageswhichareprotectedfromlowprivilegeaccess.

AbasicknowledgeofProtectedModeandOSInternalsarerequired,referto
yourAssemblyBookforthat:)Thetechniquespresentedhereareinnowaya
good/cleanwaytogettoahigherprivilegelevel,butsincetheyrequireonly
aminimalcodingeffort,theyaresometimesmoredesirabletoimplementthana
fullfledgedVxD.

1.Introduction

UnderallmodernOperatingSystems,theCPUrunsinprotectedmode,taking
advantageofthespecialfeaturesofthismodetoimplementvirtualmemory,
multitaskingetc.Tomanageaccesstosystemcriticalresources(andtothus
providestability)aOSisinneedofprivilegelevels,sothataprogramcan't
justswitchoutofprotectedmodeetc.Theseprivilegelevelsarerepresented
onthex86(Irefertox86meaning386andfollowing)CPUby'Rings',with
Ring0beingthemostprivilegedandRing3beingtheleastprivilegedlevel.
Theoretically,thex86iscapableof4privilegelevels,butWin32usesonly
twoofthem,Ring0as'KernelMode'andRing3as'UserMode'.

SinceRing0isnotneededby99%ofallapplications,theonlydocumentedway
touseRing0routinesinWin9xisthroughVxDs.ButVxDs,whilebeingtheonly
stableandrecommendedway,areworktowriteandbig,soinacoupleof
specializedsituations,otherwaystogoRing0areuseful.

TheCPUitselfhandlesprivilegeleveltransitionsintwoways:Through
Exceptions/InterruptsandthroughCallgates.CallgatescanbeputintheLDTor
GDT,InterruptGatesarefoundintheIDT.

We'lltakeadvantageofthefactthatthesetablescanbefreelywrittento
fromRing3inWin9x(NOTINNT!).

2.TheIDTmethod

Ifanexceptionoccurs(oristriggered),theCPUlooksintheIDTtothe
correspondingdescriptor.ThisdescriptorgivestheCPUanAddressandSegment
totransfercontrolto.AnInterruptGatedescriptorlookslikethis:

DD
1.Offset(1631) PPP01110000RRRRR+4
LL

2.SegmentSelector 3.Offset(015) 0

DPL==TwobitscontainingtheDescriptorPrivilegeLevel
P==Presentbit
R==Reservedbits

Thefirstword(Nr.3)containsthelowerwordofthe32bitaddressofthe
ExceptionHandler.Thewordat+6containsthehighorderword.Thewordat+2
istheselectorofthesegmentinwhichthehandlerresides.

Thewordat+4identifiesthedescriptorasInterruptGate,containsits
privilegeandthepresentbit.Now,tousetheIDTtogoRing0,we'llcreatea
newInterruptGatewhichpointstoourRing0procedure,saveanoldoneand
replaceitwithours.

Thenwe'lltriggerthatexception.InsteadofpassingcontroltoWindow'sown
handler,theCPUwillnowexecuteourRing0code.Assoonaswe'redone,we'll
restoretheoldInterruptGate.

InWin9x,theselector0028halwayspointstoaRing0CodeSegment,whichspans
theentire4GBaddressrange.We'llusethisasourSegmentselector.

TheDPLhastobe3,aswe'recallingfromRing3,andthepresentbitmustbe
set.Sothewordat+4willbe1110111000000000b=>EE00h.Thesevaluescan
behardcodedintoourprogram,wehavetojustaddtheoffsetofourRing0
Proceduretothedescriptor.Asexception,youshouldpreferrablyuseonethat
rarelyoccurs,sodonotuseint14h;)

I'lluseint9h,sinceitis(tomyknowledge)notusedon486+.

Examplecodefollows(tobecompiledwithTASM5):

bitehere

.386P
LOCALS
JUMPS
.MODELFLAT,STDCALL

EXTRNExitProcess:PROC

.data

IDTR df0 ;ThiswillreceivethecontentsoftheIDTR


;register

SavedGatedq0 ;Wesavethegatewereplaceinhere

OurGatedw0 ;Offsetloworderword
dw028h ;Segmentselector
dw0EE00h ;
dw0 ;Offsethighorderword

.code

Start:
moveax,offsetRing0Proc
mov[OurGate],ax ;Puttheoffsetwords
shreax,16 ;intoourdescriptor
mov[OurGate+6],ax

sidtfwordptrIDTR
movebx,dwordptr[IDTR+2] ;loadIDTBaseAddress
addebx,8*9 ;Addressofint9descriptorinebx

movedi,offsetSavedGate
movesi,ebx
movsd ;Savetheolddescriptor
movsd ;intoSavedGate

movedi,ebx
movesi,offsetOurGate
movsd ;Replacetheoldhandler
movsd ;withournewone

int9h ;Triggertheexception,thus
;passingcontroltoourRing0
;procedure

movedi,ebx
movesi,offsetSavedGate
movsd ;Restoretheoldhandler
movsd

callExitProcess,LARGE1

Ring0ProcPROC
moveax,CR0
iretd
Ring0ProcENDP

endStart

bitehere

3.TheLDTMethod

AnotherpossibilityofexecutingRing0Codeistoinstallasocalledcallgate
ineithertheGDTorLDT.UnderWin9xitisalittlebiteasiertousetheLDT,
sincethefirst16descriptorsinitarealwaysempty,soIwillonlygive
sourceforthatmethodhere.

ACallgateissimilartoaInterruptGateandisusedinordertotransfer
controlfromalowprivilegedsegmenttoahighprivilegedsegmentusingaCALL
instruction.

Theformatofacallgateis:

DD DDDD
1.Offset(1631) PPP011000000WWWW+4
LL CCCC

2.SegmentSelector 3.Offset(015) 0

P==Presentbit
DPL==DescriptorPrivilegeLevel
DWC==DwordCount,numberofargumentscopiedtothering0stack

Soallwehavetodoistocreatesuchacallgate,writeitintooneofthe
first16descriptors,thendoafarcalltothatdescriptortoexecuteour
Ring0code.

ExampleCode:

bitehere

.386P
LOCALS
JUMPS
.MODELFLAT,STDCALL

EXTRNExitProcess:PROC

.data

GDTR df0 ;ThiswillreceivethecontentsoftheIDTR


;register

CallPtrdd00h ;Aswe'reusingthefirstdescriptor(8)and
dw0Fh ;itslocatedintheLDTandtheprivilegelevel
;is3,ourselectorwillbe000Fh.
;Thatisbecausethelowordertwobitsofthe
;selectoraretheprivilegelevel,andthe3rd
;bitissetiftheselectorisintheLDT.

OurGatedw0 ;Offsetloworderword
dw028h ;Segmentselector
dw0EC00h ;
dw0 ;Offsethighorderword

.code

Start:
moveax,offsetRing0Proc
mov[OurGate],ax ;Puttheoffsetwords
shreax,16 ;intoourdescriptor
mov[OurGate+6],ax

xoreax,eax

sgdtfwordptrGDTR
movebx,dwordptr[GDTR+2] ;loadGDTBaseAddress
sldtax
addebx,eax ;AddressoftheLDTdescriptorin
;ebx
moval,[ebx+4] ;Loadthebaseaddress
movah,[ebx+7] ;oftheLDTitselfinto
shleax,16 ;eax,refertoyourpmode
movax,[ebx+2] ;manualfordetails

addeax,8 ;SkipNULLDescriptor

movedi,eax
movesi,offsetOurGate
movsd ;Moveourcustomcallgate
movsd ;intotheLDT

callfwordptr[CallPtr] ;ExecutetheRing0Procedure

xoreax,eax ;CleanuptheLDT
subedi,8
stosd
stosd

callExitProcess,LARGE1

Ring0ProcPROC
moveax,CR0
retf
Ring0ProcENDP

endStart

bitehere

Well,that'sallfornowfolks.ThismethodcanbeeasilychangedtousetheGDT
insteadwhichwouldsaveafewbytesincaseyouhavetooptimizeheavily.

Anyways,dousethesemethodswithcare,theywillNOTrunonNTandare
generallynotexactlyacleanorstablewaytodothesethings.

Credits&Thanks

TheIDTMethodtakenfromtheCIHvirus&Stone'sexamplesourceat
http://www.cracking.net.
TheLDTMethodwasdonebyme,butwithoutIceMans&The_OwlshelpIwould
stillbestuck,soallcreditsgotothem.

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

Therequiredtools:
MicrosoftMacroAssembler6.1x:MASMsupportofWin32programming
startsfromversion6.1.Thelatestversionis6.13which
isapatchtopreviousversionof6.11.Win98DDKincludesMASM
6.11dwhichyoucandownloadfromMicrosoftat
http://www.microsoft.com/hwdev/ddk/download/win98ddk.exe
Butbewarned,thismonstrosityishuge,18.5MBinsize.MASM6.13
patchcanalsobedownloadedfrom
ftp://ftp.microsoft.com/softlib/mslfiles/ml613.exe
Microsoftimportlibraries:Youcanusetheimportlibrariesfrom
VisualC++.SomeareincludedinWin98DDK.
Win32APIReference:YoucandownloaditfromBorland'ssite:
ftp://ftp.borland.com/pub/delphi/techpubs/delphi2/win32.zip

Here'sabriefdescriptionoftheassemblyprocess.

MASM6.1xcomeswithtwoessentialtools:ml.exeandlink.exe.ml.exeisthe
assembler.Ittakesintheassemblysourcecode(.asm)andproducesanobject
file(.obj).Anobjectfileisanintermediatefilebetweenthesourcecode
andtheexecutablefile.Itneedssomeaddressfixupswhicharetheservices
providedbylink.exe.Link.exemakesanobjectfileintoanexecutablefileby
severalmeanssuchasaddingthecodesfromothermodulestotheobjectfiles
orprovidingtheaddressfixups,addingresouces,etc.

Forexample:
mlskeleton.asm>thisproducesskeleton.obj
linkskeleton.obj>thisproducesskeleton.exe

Theabovelinesaresimplificationofcourse.Intherealworld,youmustadd
severalswitchestoml.exeandlink.exetocustomizeyourapplication.Also
therewillbeseveralfilesyoumustlinkwiththeobjectfileinorderto
createyourapplication.

Win32programsruninprotectedmodewhichisavailablesince80286.But80286
isnowhistory.Soweonlyhavetoconcernourselveswith80386andits
descendants.WindowsruneachWin32programinseparatedvirtualspace.That
meanseachWin32programwillhaveitsown4GBaddressspace.Eachprogramis
aloneinitsaddressspace.ThisisincontrasttothesituationinWin16.All
Win16programscan*see*eachother.NotsoinWin32.Thisfeaturehelpsreduce
thechanceofoneprogramwritingoverotherprogram'scode/data.

Memorymodelisalsodrasticallydifferentfromtheolddaysofthe16bit
world.UnderWin32,weneednotbeconcernedwithmemorymodelorsegment
anymore!There'sonlyonememorymodel:Flatmemorymodel.There'snomore64K
segments.Thememoryisalargecontinuousspaceof4GB.Thatalsomeansyou
don'thavetoplaywithsegmentregisters.Youcanuseanysegmentregisterto
addressanypointinthememoryspace.That'saGREAThelptoprogrammers.This
iswhatmakesWin32assemblyprogrammingaseasyasC.

WewillexamineamiminalskeletonofaWin32assemblyprogram.We'lladdmore
fleshtoitlater.Here'stheskeletonprogram.Ifyoudon'tunderstandsomeof
thecodes,don'tpanic.I'llexplaineachofthemlater.

.386
.MODELFlat,STDCALL
.DATA
<Yourinitializeddata>
......
.DATA?
<Youruninitializeddata>
......
.CONST
<Yourconstants>
......
.CODE
<label>
<Yourcode>
.....
end<label>
That'sall!Let'sanalyzethisskeletonprogram.

.386
Thisisanassemblerdirective,tellingtheassemblertouse80386instruction
set.Youcanalsouse.486,.586butthesafestbetistostickto.386.

.MODELFLAT,STDCALL
.MODELisanassemblerdirectivethatspecifiesmemorymodelofyourprogram.
UnderWin32,there'sonlyonmodel,FLATmodel.STDCALLtellsMASMabout
parameterpassingconvention.Parameterpassingconventionspecifiestheorder
ofparameterpassing,lefttorightorrighttoleft,andalsowhowill
balancethestackframeafterthefunctioncall.

UnderWin16,therearetwotypesofcallingconvention,CandPASCALCcalling
conventionpassesparameterstothefunctionfromrighttoleft,thatis,the
rightmostparameterispushedonthestackfirst.Thecallerisresponsiblefor
balancingthestackframeafterthecall.Forexample,inordertocalla
functionnamedfoo(intfirst_param,intsecond_param,intthird_param)inC
callingconventiontheasmcodeswilllooklikethis:

push[third_param] ;Pushthethirdparameter
push[second_param] ;Followedbythesecond
push[first_param] ;Andthefirst
callfoo
addsp,12 ;Thecallerbalancesthestackframe

PASCALcallingconventionisthereverseofCcallingconvention.Itpushes
parametersonthestackfromlefttorightandthecalleeisresponsiblefor
thestackbalancingafterthecall.

Win16adoptsPASCALconventionbecauseitproducessmallercodes.Cconvention
isusefulwhenyoudon'tknowhowmanyparameterswillbepassedtothe
functionasinthecaseofwsprintf().Inthecaseofwsprintf(),thefunction
hasnowaytodeterminebeforehandhowmanyparameterswillbepushedonthe
stack,soitcannotbalancethestackcorrectly.Thecalleristheonewho
knowshowmanybytesarepushedonthestacksoit'srightandproperthatit's
alsotheonewhobalancesthestackframeafterthecall.

STDCALListhehybridofCandPASCALconvention.Itpushesparametersonthe
stackfromrighttoleftbutthecalleeisresponsibleforstackbalancing
afterthecall.Win32platformuseSTDCALLexclusively.Exceptinonecase:
wsprintf().YoumustuseCcallingconventionwithwsprintf().

.DATA
.DATA?
.CONST
.CODE
Allfourdirectivesarewhatarecalledsections.Youdon'thavesegmentsin
Win32anymore,remember?Butyoucandivideyourentireaddressspaceinto
logicalsections.Thestartofonesectiondenotestheendoftheprevious
section.Therearetwogroupsofsection:dataandcode.Datasectionsare
dividedinto3categories:

*.DATAThissectioncontainsinitializeddataofyourprogram.
*.DATA?Thissectioncontainsuninitializeddataofyourprogram.
Sometimesyoujustwanttopreallocatesomememorybutdoesn'twantto
initializeit.Thissectionexistsforthatpurpose.
*.CONSTThissectioncontainsdeclarationofconstantsusedbyyour
program.Constantsinthissectioncanneverbemodifiedinyour
program.Theyarejust*constant*.

Youdon'thavetouseallthreesectionsinyourprogram.Declareonlythe
section(s)youwanttouse.

There'sonlyonesectionforcode:.CODE.Thisiswhereyourcodesreside.
Example:

<label>
end<label>

...where<label>isanyarbitrarylabelisusedtospecifytheextentofyour
code.Bothlabelsmustbeidentical.Allyourcodesmustresidebetween
<label>andend<label>

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

WewillcreateafullyfunctionalWindowsprogramthatdisplaysamessagebox
saying"Win32assemblyisgreat!".

WindowspreparesawealthofresourcesforusebyWindowsprograms.Centralto
thisistheWindowsAPI(ApplicationProgrammingInterface).WindowsAPIisa
hugecollectionofveryusefulfunctionsthatresidesinWindowsitself,ready
tobeusedbyanyWindowsprograms.

Thesefunctionsarestoredinseveraldynamiclinkedlibraries(DLLs)suchas
kernel32.dll,user32.dllandgdi32.dll,tonameafew.Kernel32.dllcontains
APIfunctionsthatdealwithmemoryandprocessmanagement.User32.dllcontrols
theuserinterfaceaspectsofyourprograms.Gdi32.dllisresponsiblefor
graphicsoperation.Otherthan"themainthree",thereareotherDLLsthatyour
programcanmakeuseof,providedyouhaveenoughinformationaboutthedesired
APIfunctionsstoredinthem.

WindowsprogramsdynamicallylinktotheseDLLs,i.e.thecodesofAPI
functionsarenotincludedintheexecutablefile.Thisisverydifferentfrom
what'scalledstaticlinkinginwhichactualcodesfromsoftwarelibrariesare
includedintheexecutablefiles.Inorderforprogramstoknowwheretofind
thedesiredAPIfunctionsatruntime,enoughinformationmustbeembeddedinto
theexecutablefileforittobeabletoselectthecorrectDLLsandcorrect
functions.Thatinformationisinimportlibraries.Youmustlinkyour
programswiththecorrectimportlibrariesoritwillnotbeabletolocate
thedesiredAPIfunctions.

TherearetwotypesofAPIfunctions:OneforANSIandtheotherforUnicode.
ThenameofAPIfunctionsforANSIarepostfixedwith"A",eg.MessageBoxA.
ThoseforUnicodearepostfixedwith"W"(forWideChar,Ithink).

Windows95nativelysupportsANSIandWindowsNTUnicode.Butmostofthetime,
youwilluseanincludefilewhichcandetermineandselecttheappropriateAPI
functionsforyourplatform.JustrefertotheAPIfunctionnamewithoutthe
postfix.

I'llpresentthebareprogramskeletonbelow.Wewillfillitoutlater.

.386
.modelflat,stdcall
.data
.code
Main:
endMain

EveryWindowsprogrammustcallanAPIfunction,ExitProcess,whenitwantsto
quittoWindows.Inthisrespect,ExitProcessisequivalenttoint21h,ah=4Ch
inDOS.

Here'sthefunctionprototypeofExitProcessfromwinbase.h:

voidWINAPIExitProcess(UINTuExitCode);

voidmeansthefunctiondoesnotreturnanyvaluetothecaller.
WINAPIisanaliasofSTDCALLcallingconvention.
UINTisadatatype,"unsignedinteger",whichisa32bitvalueunderWin32
(it'sa16bitvalueunderWin16)
uExitCodeisthe32bitreturncodetoWindows.Thisvalueisnotusedby
Windowsasofnow.

InordertocallExitProcessfromanassemblyprogram,youmustfirstdeclare
thefunctionprototypeforExitProcess.

.386
.modelflat,stdcall
ExitProcess PROTO :DWORD
.data
.code
Main:
invokeExitProcess,0
endMain

That'sit.YourfirstworkingWin32program.Saveitunderthenamemsgbox.asm.
Assumingml.exeisinyourpath,assemblemsgbox.asmwith:

ml/c/coff/Cpmsgbox.asm

/ctellsMASMtoassemblethesourcefileintoanobjectfileonly.Donot
invokeLink.exeautomatically.
/cofftellsMASMtocreate.objfileinCOFFformat.
/CptellsMASMtopreservecaseofuseridentifiers

Thengoonwithlink:

link/SUBSYSTEM:WINDOWS/LIBPATH:c:\masm\libmsgbox.obj
kernel32.lib

/SUBSYSTEM:WINDOWSinformsLink.exeonwhichplatformtheexecutableis
intendedtorun
/LIBPATH:<pathtoimportlibrary>tellsLinkwheretheimportlibraries
are.InmyPC,they'relocatedinc:\masm\lib.

Nowthatyougetmsgbox.exe.Goon,runit.You'llfindthatitdoesnothing.
Well,wehaven'tputanythinginterestinginityet.Butit'saWindows
programnonetheless.Andlookatitssize!InmyPC,itis1,536bytes.
Theline:

ExitProcessPROTO:DWORD

isafunctionprototype.Youcreateonebydeclaringthefunctionnamefollowed
bythekeyword"PROTO"andlistsofdatatypesoftheparametersprefixedby
colons.MASMusesfunctionprototypestotypecheckingwhichwillpreventnasty
stackerrorsthatmaypassunnoticedotherwise.

Thebestplaceforfunctionprototypesisinanincludefile.Youcancreatean
includefilefulloffrequentlyusedfunctionprototypesanddatastructures
andincludeitatthebeginningofyourasmsourcecode.

YoucalltheAPIfunctionbyusing"invoke"keyword:

invokeExitProcess,0

INVOKEisreallyakindofhighlevelcall.Itchecksnumberandtypesof
parametersandpushesparametersonthestackaccordingtothespecified
callingconvention(inthiscase,stdcall).ByusingINVOKEinsteadofanormal
call,youcanpreventstackerrorsfromincorrectparameterpassing.Very
useful.Thesyntaxis:

INVOKEexpression[,arguments]

whereexpressionisalabelorfunctionname.

Nextwe'regoingtoputamessageboxinourprogram.Itsfunctiondeclaration
is:

intWINAPIMessageBoxA(HWNDhwnd,LPCSTRlpText,LPCSTRlpCaption,UINT
uType);

hwndisthehandletoparentwindow
lpTextisapointertothetextyouwanttodisplayintheclientareaofthe
messagebox
lpCaptionisapointertothecaptionofthemessagebox
uTypespecifiestheiconandthenumberandtypeofbuttonsonthemessage
box

UnderWin32,HWND,LPCSTR,andUINTareall32bitsinsize.

Let'smodifymsgbox.asmtoincludethemessagebox.

.386
.modelflat,stdcall
ExitProcess PROTO :DWORD
MessageBoxAPROTO:DWORD,:DWORD,:DWORD,:DWORD
.data
MsgBoxCaptiondb"OurFirstProgram",0
MsgBoxTextdb"Win32AssemblyisGreat!",0
.const
NULL equ0
MB_OK equ0
.code
Main:
INVOKEMessageBoxA,NULL,ADDRMsgBoxText,ADDRMsgBoxCaption,MB_OK
INVOKEExitProcess,NULL
endMain

Assembleitby:
ml/c/coff/Cpmsgbox.asm
link/SUBSYSTEM:WINDOWS/LIBPATH:c:\masm\libmsgboxkernl32.lib
user32.lib

Youhavetoincludeuser32.libinyourLinkparameter,sincelinkinfoof
MessageBoxAisinuser32.lib.

You'llseeamessageboxdisplayingthetext"Win32AssemblyisGreat!".Let's
lookagainatthesourcecode:

Wedefinetwozeroterminatedstringsin.datasection.Rememberthatall
stringsinWindowsmustbeterminatedwithzero(ASCIIZ).

Wedefinetwoconstantsin.constsection.Weuseconstantstoimprovethe
clarityofthesourcecode.

LookattheparametersofMessageBoxA.ThefirstparameterisNULL.This
meansthatthere'snowindowthat*owns*thismessagebox.

Theoperator"ADDR"isusedtopasstheaddressofthelabeltothefunction.
ThisoperatorisspecifictoMASM.NoTASMequivalentexists.Itfunctionslike
"OFFSET"operatorbutwithsomedifferences:
1.Itdoesn'tacceptforwardreference.Ifyouwanttouse"ADDRfoo",
youhavetodeclare"foo"beforeusingADDRoperator.
2.Itcanbeusedwithalocalvariable.Alocalvariableisthe
variablethatiscreatedonthestack.OFFSEToperatorcannotbe
usedinthissituationbecausetheassemblerdoesn'tknowthetrue
addressofthelocalvariableatassembletime.

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::........................THE.C.STANDARD.LIBRARY.IN.ASSEMBLY
The_itoa,_ltoaand_ultoafunctions
byXbios2

ATTENTIONI:
ThisisbasedonBorland'sC++4.02.WheneverpossibleI'vecheckeditwithany
otherlibrary/programcontainingthespecificfunctions,butdifferencesmay
existbetweenthisandyourversionofC.Alsothisisstrictly32bitcode,
Windowscompiler.NoDOSorUNIX.]

ATTENTIONII:
Sizecomparisonsareextremelyeasytodo.Speedcomparison'saren't.Thediff
erencesinspeedIgivearebasedonRDTSCtimings,buttheyDON'Ttakeinto
accountextremecases.That'swhyIdon'tgiveexactclockcycles.Ofcourseif
youneedexactclockcyclesforyourPentiumII,youcanalwaysbuymeone:)

TheClanguageoffersthreefunctionstoconvertanintegertoASCII:

char*itoa(intvalue,char*string,intradix);
char*ltoa(longvalue,char*string,intradix);
char*ultoa(unsignedlongvalue,char*string,intradix);

_itoaand_ltoado_exactly_thesamething.Thisisbecauseaninteger_is_a
longin32bitcode.Yettheyaredifferent:_itoahassome_completely_
uselesscodeinit(in16bitthiscodewouldsignextendvalueifradix=10).
Yettheresultisalwaysthesame,so_ltoafromhereonmeansboth_ltoaand
_itoa._ultoaisexactlythesameas_ltoaand_itoa,exceptwhenradix=10and
value<0.

Anywayallthesefunctionscallthisfunction:

___longtoa(value,*string,radix,signed,char10)

Thefirstthreeparametersarepassed'asis',signedissetto1by_ltoaif
radix=10elseitissetto0andchar10isthecharacterthatcorrespondsto10
ifradix>10,andisalwayssetto'a'(___longtoaisalsousedbyprintf,which
hasanoptiontohaveuppercasecharsinHex).

___longtoadoesthefollowing(anditdoesitwithbadlywrittencode):

1.Checksthat2<=radix<=36,ifitisn'treturns'0'
2.Ifsigned=1andvalue<0adda''tothestringandnegthevalue
3.Loop1:createapseudostringinthestack,reversed
4.Loop2:convertandcopythepseudostringintostring

Thecheckonradixisnecessarybecause:
radix=0wouldgenerateanINT0(dividebyzero)
radix=1wouldputtheprograminaninfiniteloop,destroyingthestack
radix=37forvalue=36wouldreturn'}',thecharacterafter'z'

Thetwoloopsarenecessarybecauseofthewaytheconversionisdone(seecode
later).Toimplementasingleloopconversion,thenumberofdigitsshouldbe
calculatedinadvance,whichresultsinlessefficientcode(thenumberof
digitsinvalueisn=(int)(log(value)/log(radix))+1,butusingonemoreloopis
muchfaster).

IncludingthedisassemblyofC'sfunctionswouldcreateareallylargearticle,
andanywaythey'rejustexamplesofreallybadcode.Sostraighttotheresult:

ltoa proc
cmp dwordptr[esp+0Ch],10
sete ch
mov cl,'a''0'10
jmp shortlongtoa

ultoa:
mov cx,'a''0'10

longtoa:
push ebx
push edi
push esi
sub esp,24h
mov ebx,[esp+3Ch] ;radix
mov eax,[esp+34h] ;value
mov edi,[esp+38h] ;string
cmp ebx,2
jl short_ret
cmp ebx,36
jg short_ret
or eax,eax
jge shortskip
cmp byteptrch,0 ;_ltoa?
jz shortskip
mov byteptr[edi],''
inc edi
neg eax
skip: mov esi,esp

loop1: xor edx,edx


div ebx
mov [esi],dl
inc esi
or eax,eax
jnz loop1

loop2: dec esi


mov al,[esi]
cmp al,10
jl shortnochar
add al,cl
nochar:add al,'0'
stosb
cmp esi,esp
jg shortloop2

_ret: mov byteptr[edi],0


mov eax,[esp+38h]
add esp,24h
pop esi
pop edi
pop ebx
ret
ltoa endp

Thisisa3into1procedure.ltoaandultoatakethesameparametersasthe
standardCfunctions.longtoawaschangedtotakefromthestackthesame
parametersasltoaandultoa,whilesignedandchar10arepassedinCHandCL
respectively.Thiswayltoaandultoa'see'longtoaas'their'code,notasa
differentprocedure(thisistoavoidacommonprobleminC,proceduresthat
just'forward'theirparameterstoanotherfunction).

Thiscodecompilesto102bytes(anditcouldbeoptimizedtogainsomemore
bytes)whereasthestandardCcodetakes270bytes.Specifically:

functionCsizeAsmsize

itoa 60 0
ltoa 40 12
ultoa 27 4
longtoa143 86

total270 102

Italsoruns2xfasterthanltoa.Andofcourse,thisisafullyCcompatible
versionofltoaandultoa.OfcourseitcanbechangedfromCcompatibleto
suitspecificneeds(e.gmakeitstdcallinsteadofcdecl,orifspeedandsize
areneededremovethecheckfortheradix,andsoon...)

Anyway,itisratherstrangethatyou'lleverusevaluesofradixotherthan2,
8,10or16.Soifspeedorsizeisofessence,abetter,morespecificroutine
canbewritten.Forexample,considerthisroutinewhichstoresthevalueof
EAXasabinarynumberattheaddressspecifiedbyEDI:

ultob proc
mov ecx,32
more1: shl eax,1
dec ecx
jc more2
jnl more1
more2: setc dl
add dl,'0'
shl eax,1
mov [edi],dl
inc edi
dec ecx
jnl more2
mov [edi],al
ret
ultob endp

Thisruns14xfasterthanCltoa,and7xfasterthanAsmltoa,andisonly29
byteslong.Butthisarticleislongenough,sowaitforanotherarticleon
specific'ltoa'functions(whoknows,maybeifIdecidetowritea'printf'
functioninAsm,whichwouldusethem...).

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

Essentiallythisarticleisanexcusetocombinetwoofmyfavoritecoding
interests:theLinuxoperatingsystemandassemblylanguageprogramming.Both
oftheseneed(orshouldneed)nointroduction;likeWin32assembly,Linux
assemblyrunsin32bitprotectedmode...howeverithasthedistinctadvantage
ofallowingyoutocalltheCstandardlibraryfunctionsaswellasanyofthe
usualLinux"shared"libraryfunctions.Ihavebegunwithabriefintroduction
oncompilingassemblylanguageprogramsinLinux;forgreaterreadabilityyou
maywanttoskipoverthistothe"Basics"section.

CompilingAndLinking

ThetwomainassemblersforLinuxareNasm,the(free)NetwideAssembler,and
GAS,the(alsofree)GnuAssemblerwhichisintegratedintoGCC.Iwillfocus
onNasminthisarticleandleaveGASforalaterdate,asitusestheAT&T
syntaxandthuswouldrequirealengthyintroduction.

NasmshouldbeinvokedwiththeELFformatoption("nasmfelfhello.asm");
theresultingobjectislinkedwithGCC("gcchello.o")toproducethefinal
ELFbinary.ThefollowingscriptcanbeusedtocompileASMmodules;Iwrote
ittobeverysimple,soallitdoesistakethefirstfilenamepassedtoit
(Irecommendnamingitwitha".asm"extension),compileitwithnasm,and
linkitwithgcc.

#!/bin/sh
#assemble.sh=========================================================
outfile=${1%%.*}
tempfile=asmtemp.o
nasmo$tempfilefelf$1
gcc$tempfileo$outfile
rm$tempfilef
#EOF==================================================================

TheBasics

Itisbest,ofcourse,tostartoffwithanexamplebeforelaunchingintothe
OSdetails.Hereisaverybasic,"helloworld"styleprogram:
;asmhello.asm========================================================
globalmain
externprintf

section.data
msg db "Helloooooo,nurse!",0Dh,0Ah,0
section.text
main:
pushdwordmsg
callprintf
popeax
ret
;EOF=================================================================
Aquickrundown:the"globalmain"mustbedeclaredglobalandsinceweare
usingtheGCClinker,theentrypointmustbenamed"main"fortheOSloader.
The"externprintf"issimplyadeclarationforthecalllaterintheprogram;
notethatthisisallthatisneeded;theparametersizesdonotneedtobe
declared.Ihavesectionedthisexampleintothestandard.dataand.text
sections,thoughthisisnotstrictlynecessaryonecouldgetbywithonlya
.textsegment,justasinDOS.

Inthebodyofthecode,notethatyoumustpushtheparameterstothecall,
andinNasmyoumustdeclarethesizeofallambiguous(i.e.nonregister)
data:hencethe"dword"qualifier.Notethatjustasinotherassemblers,Nasm
assumesthatanymemory/labelreferenceisintendedtomeantheaddressofthe
memorylocationorlabel,notitscontents.Thus,tospecifytheaddressof
thestring'msg'youwoulduse'pushdwordmsg',whiletospecifythecontents
ofthestring'msg'youwoulduse'pushdword[msg]'(notethiswillonly
containthefirst4bytesof'msg').Asprintfrequiresapointertoastring,
wewillspecifytheaddressof'msg'.

Thecalltoprintfisprettystraightforward.Notethatyoumustcleanupthe
stackaftereverycallyoumake(seebelow);thus,havingPUSHedadword,I
POPadwordfromthestackintoa"throwaway"register.Linuxprogramsend
simplywithaRETtotheOS,aseachprocessisspawnedfromtheshell(orPID
1;)andendsbyreturningcontroltoit.

NoticethatinLinuxyouusethestandardsharedlibrariesthatareshipped
withtheOSinlieuofan"API"orInterruptServices.Allexternalreferences
willbetakencareofbytheGCClinkerwhichtakesalotoftheworkloadoff
theasmcoder.Onceyougetusedtothebasicquirks,codingassemblyinLinux
isactuallyeasierthanonaDOSbasedmachine!

TheCCallingSyntax

LinuxusestheCcallingconventionmeaningthatargumentsarepushedontothe
stackinreverseorder(lastargfirst),andthatthecallermustcleanupthe
stack.Youcandothiseitherbypoppingvaluesfromthestack:
pushdwordszText
callputs
popecx
orbydirectlymodifyingESP:
pushdwordszText
callputs
addesp,4

Resultsfromthecallarereturnedineaxoredx:eaxifthevalueisgreater
than32bit.EBP,ESI,EDI,andEBXareallsavedandrestoredbythecaller.
Notethatyoumustpreserveanyotherregistersyouuse,asthefollowingwill
illustrate:
;loop.asm=================================================================
globalmain
externprintf
section.text
msg db "HoodooVoodooWeedooVoodoo",0Dh,0Ah,0
main:
movecx,0Ah
pushdwordmsg
looper:
callprintf
looplooper
popeax
ret
;EOF======================================================================
Onfirstglancethislooksprettysimple:sinceyouaregoingtousethesame
stringonthe10printf()calls,youdonotneedtocleanupthestack.Yet
whenyoucompilethis,theloopneverstops.Why?Becausesomewhereinthe
printf()callECXisbeingusedandisn'tsaved.Sotomakeyourloopwork
properlyyoumustsavethecountvalueinECXbeforethecallandrestoeit
afterwards,asso:
;loop.asm================================================================
globalmain
externprintf

section.text
msg db "HoodooVoodooWeedooVoodoo",0Dh,0Ah,0
main:
movecx,0Ah
looper:
pushecx ;saveCount
pushdwordmsg
callprintf
popeax ;cleanupstack
popecx ;restoreCount
looplooper
ret
;EOF======================================================================

I/OPortProgramming

Butwhataboutdirecrhardwareaccess?InLinuxyouneedakernelmodedriver
todoanythingreallytricky...thismeansyourprogramwillendupbeingtwo
parts,onekernelmodethatprovidesthedirecthardwarefunctionality,the
otherusermodetoprovideaninterface.Thegoodnewsisthatyoucanstill
accessportsusingtheIN/OUTcommandsfromausermodeprogram.

ToaccesstheI/OportsyourprogrammustbegrantedpermissionbytheOS;to
dothat,youmustmakeanioperm()call.Thisfunctioncanonlybecalledbya
userwithrootaccess,soyoumusteithersetuid()theprogramtorootorrun
theprogramasroot.Theioperm()hasthefollowingsyntax:

ioperm(longStartingPort#,long#Ports,BOOLToggleOnOff)

whichmeansthat'StartingPort#'specifiesthefirstportnumbertoaccess(0
isport0h,40hisport40h,etc),'#Ports'specifieshowmanyportstoaccess
(i.e.,'StartingPort#=30h'and'#Ports=10'wouldprovideaccesstoports
30h39h),and'ToggleOnOff'enablesaccessifTRUE(1)ordisablesaccessif
FALSE(0).

Oncethecalltoioperm()ismade,therequestedportsmaybeaccessas
normal.Theprogramcancallioperm()anynumberoftimesanddoesnotneedto
makeasubsequentioperm()call(thoughtheexamplebelowdoesso)astheOS
willtakecareofthis.

;io.asm====================================================================
BITS32
GLOBALszHello
GLOBALmain
EXTERNprintf
EXTERNioperm

SECTION.data
szText1db'EnablingI/OPortAccess',0Ah,0Dh,0
szText2db'DisablingI/OPortAcess',0Ah,0Dh,0
szDone db'Done!',0Ah,0Dh,0
szErrordb'Errorinioperm()call!',0Ah,0Dh,0
szEqualdb'Output/Inputbytesareequal.',0Ah,0Dh,0
szChangedb'Output/Inputbyteschanged.',0Ah,0Dh,0

SECTION.text

main:
pushdwordszText1
callprintf
popecx
enable_IO:
pushword1 ;enablemode
pushdword04h;fourports
pushdword40h;startwithport40
callioperm ;MustbeSUID"root"forthiscall!
addESP,10 ;cleanupstack(method1)
cmpeax,0 ;checkioperm()results
jneError

;PortProgrammingPart
SetControl:
moval,96 ;R/WlowbyteofCounter2,mode3
out43h,al ;port43h=controlregister
WritePort:
movbl,0EEh;valuetosendtospeakertimer
moval,bl
out42h,al ;port42h=speakertimer
ReadPort:
inal,42h
cmpal,bl ;byteshouldhavechangedthisISatimer:)
jneByteChanged
BytesEqual:
pushdwordszEqual
callprintf
popecx
jmpdisable_IO
ByteChanged:
pushdwordszChange
callprintf
popecx
;EndPortProgrammingPart

disable_IO:
pushdwordszText2
callprintf
popecx
pushword0 ;disablemode
pushdword04h;fourports
pushdword40h;startwithport40h
callioperm
popecx ;cleanupstack(method2)
popecx
popcx
cmpeax,0 ;checkioperm()results
jneError
jmpExit
Error:
pushdwordszError
callprintf
popecx
Exit:
ret
;EOF======================================================================

UsingInterruptsInLinux

Linuxisasharedlibraryenvironmentrunninginprotectedmode,meaningthere
arenointerruptservices.Right?

Wrong.InoticedanINT80callonsomeGASsamplesourcecodewiththe
comment"sys_write(ebx,ecx,edx)".ThisfunctionispartoftheLinuxsyscall
interface,whichmeansthattheinterrupt80mustbeagateintothesyscall
services.PokingaroundintheLinuxsourcecode(andignoringwarningsto
NEVERusetheINT80interfaceasthefunctionnumbersmaybechangedatany
time),Ifoundthe"systemcallnumbers"thatis,whatfunction#topasson
toINT80foreachsyscallroutineinthefileUNISTD.H.Thereare189of
them,soIwillnotlistthemhere...butifyouaregoingtobedoingLinux
assembly,doyourselfafavorandprintthisfileout.

WhencallingINT80h,eaxmustbesettothedesiredfunctionnumber.Any
parameterstothesyscallroutinemustbeplacedinthefollowingregistersin
order:

ebx,ecx,edx,esi,edi

sothatparameteroneisplacedinebx,parameter2inecx,etc.Notethat
thereisnostackusedtopassvaluestoasyscallroutine.Theresultofthe
callwillbereturnedineax.

Otherthanthat,theINT80interfaceisthesameasregularcalls(onlyabit
morefun;).ThefollowingprogramdemonstratesasimpleINT80hcallinwhich
aprogramchecksanddisplayitsownPID.Notetheuseofprintf()format
stringitisbesttopsuedocodethisasaCcallfirst,thenmaketheformat
stringaDBandtopusheachvariablepassed(%s,%d,etc).TheCstructure
forthiscallwouldbe

printf("%d\n",curr_PID);

Notealsothattheescapesequences("\n")arenotallthatreliablein
assembly;Ihadtousethehexvalues(0Ah,0Dh)fortheCR\LF.

;pid.asm====================================================================
BITS32
GLOBALmain
EXTERNprintf

SECTION.data
szText1db'GettingCurrentProcessID...',0Ah,0Dh,0
szDone db'Done!',0Ah,0Dh,0
szErrordb'Errorinint80!',0Ah,0Dh,0
szOutputdb'%d',0Ah,0Dh,0 ;weirdformattingisforprintf()

SECTION.text
main:
pushdwordszText1;openingmessage
callprintf
popecx
GetPID:
moveax,dword20;getpid()syscall
int80h ;syscallINT
cmpeax,0 ;therewillneverbePID0!:)
jbError
pusheax ;passreturnvaluetoprintf
pushdwordszOutput;passformatstringtoprintf
callprintf
popecx ;cleanupstack
popecx
pushdwordszDone;endingmessage
callprintf
popecx
jmpExit
Error:
pushdwordszError
callprintf
popecx
Exit:
ret
;EOF=====================================================================

FinalWords

MostofthetroubleisgoingtocomefromgettingusedtoNasmitself.While
nasmdoescomewithamanpage,itdoesnotbydefaultinstallit,soyoumust
moveit(cpormv)from
/usr/local/bin/nasm0.97/nasm.man
to
/usr/local/man/man1/nasm.man
Theformattingisalittlemessedup,butthatiseasilyfixedusingthenroff
directives.ItstilldoesnotgiveyoutheentireNasmdocumentation,however;
forthat,copynasmdoc.txtfrom
/usr/local/bin/nasm0.97/doc/nasmdoc.txt
to
/usr/local/man/man1/nasmdoc.man
Nowyoucaminvokethenasmmanpagewith'mannasm'andthenasmdocumentation
with'mannasmdoc'.

Forfurtherinformation,checkoutthefollowing:
LinuxAssemblyLanguageHOWTO
LinuxI/OPortProgrammingMiniHOWTO
Jan'sLinux&AssemblerHomePage(bewoner.dma.be/JanW/eng.html)

AlsoIoweabitofthankstoJeffWeeksatcode^xsoftware(gameprog.com/codex)
forforwardingmeacoupleofGAShelloworld'sinthedarkdaysbeforeI
foundJan'spage.

::/\::::::.
:/___\:::::::.
/|\::::::::.
:|_/\:::::::::.
:|_|\ \::::::::::.
:::\_____\:::::::::::...........................................ISSUE.CHALLENGE
11byteProgramDisplaysItsCommandLine
byXbios2

TheChallenge

Writean11byteprogramthatdisplaysitscommandline.

TheSolution

Beforesayingthattheseprogramswon'twork,trythem.Someofthemworkonly
afteryou'verunthemtwice.Anyway,they'vebeentestedbothunderWindows
andplainDOSandtheywork.Believeitornot,thesearethefirstprograms
I'veeverwritteninDOS,soIjusttriedvariousideasuntilsomeworked,even
thoughtIthoughttheywouldn't...:)

ThecommandlineinDOSisfoundinthePSP(ProgramSegmentPrefix)whichin
.COMfilesoccupiesthefirst100hbytesinthesegment.Atoffset80h,a
<count,char>string(firstbyteislengthofstring,andnbytesfollow)
containseverythingtypedafterthefilename.Thelastcharacterinthisstring
isaCR(carriagereturn).

Therequestedprogramshouldbecomposedofthreeparts:

1.setuppointerstodata
2.displaydata
3.exit

ActuallyallthefollowingprogramsDON'Tincludepart3,butreadon.The
data(commandline)canbeprintedeitherasasinglestring,orcharacterby
character.

APPROACH1:Printsinglestring

Forthefirstapproachtherearetwointerrupts:
1.INT21,9 ;write$terminatedstring
2.INT21,40 ;writetofileusinghandle

Forthefirstcase,part2wouldbe:
mov ah,9
mov dx,81h
int 21h
thatmakes7bytes,leavingonly4bytestoreplacethelastCRwitha'$',
whicharetoofew.(Actually,iftheuserwouldtypea$asthelastcharacter
inthecomandline,thiswouldmakethesmallestpossibleprogram.)Theshort
estprogramImanagedtowriteis:
shr si,1 ;D1EE
lodsb ;AC
push si ;56
add si,ax ;03F0
mov byteptr[si],'$' ;C60424
xcgh bp,ax ;95
pop dx ;5A
int 21 ;CD21

Forthesecondcase,thesmallestprogramwouldbethis:
;SolutionI
mov dx,81h ;BA8100
mov cl,ds:[80h] ;8A0E8000
mov ah,40h ;B440
int 21h ;CD21

Thefirsttwolinesarepart1(setuppointers)andtheothertwoarepart2
(displaystring).Ifyouthinkthatsomethingismissingyou'reright:wedon't
setBX(thehandle).

APPROACH2:Printcharbychar

Forthesecondapproachtherearetwointerrupts:
1.INT21,2 ;writecharindl
2.INT29 ;writecharinal

Ofcoursethesecondinterruptisbetter,sincethereisnoneedtoloadah
withafunctionvalue.Inaddition,INT29readsthecharfromAL,soitcanbe
usedtogetherwithLODSB.

Thefirstwaytoimplementthisapproachistominimizepart2(displayloop).
Aprogramthatdoesthisisthefollowing:
;SolutionII
mov si,80h;BE8000
lodsb ;AC
mov cl,al ;8AC8
more: lodsb ;AC
int 29h ;CD29
loop more ;E2FB

ThisprogramprintedCXcharacters.ThesecondwaytoprintthestringistoprintuptotheCR.Hereishow:
;SolutionIII
mov si,81h ;BE8100
more: lodsb ;AC
int 29h ;CD29
cmp al,13 ;3C0D
jne more ;75F9
nop ;90

Yes,thelastinstructionISaNOP.Sowehavean11byteprogramthatworks,
andevenhasaNOPinit.RemovingtheNOPcreatesanevencrazierprogramthat
is10byteslong,displaysit'scommandlineANDwaitsforakeypressbefore
terminating...ActuallysolutionII,bysubstitutingMOVSI,80hwithSHRSI,1,
doesthesamething(10bytesthatdisplaythecommandlineandwaitforthe
usertopressakey).

BTW:Ireallydon'tknowwhytheseprogramswork,thoughIhaveoneortwo
theories...

NextIssueChallenge

WritethesmallestpossiblePEprogram(win32)thatoutputsit'scommandline.

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

TopNextIssue

Das könnte Ihnen auch gefallen