News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Calling WSAStartup leads to ACCESS_VIOLATION

Started by phyisio, July 04, 2023, 10:00:55 PM

Previous topic - Next topic

phyisio

Hello all! Now that I've introduced myself ill get right to asking stupid questions.
Im trying to call WSAStartup in x64, ive looked up the structs i need, verified that they get initialialissed at th right place, with 0s...
But once inside the call, there is a moment i get anc access_violation exception. As im neww to debugging x64, I have trouble my mistake. I imagine its either a stack problem or a pointer that is not initialised the intended way.
Here is my code:

extrn WSAStartup: PROC
extrn WSASocketA: PROC
extrn WSAConnect: PROC
extrn CreateProcessA: PROC
extrn ExitProcess: PROC

WSADESCRIPTION_LEN EQU 256
WSASYS_STATUS_LEN EQU 128

_WSADATA STRUCT
    wVersion WORD ?
    wHighVersion WORD ?
    szDescription BYTE (WSADESCRIPTION_LEN + 1) dup (?)
    szSystemStatus BYTE (WSASYS_STATUS_LEN + 1) dup (?)
    iMaxSockets WORD ?
    iMaxUdpDg WORD ?
    lpVendorInfo QWORD ?
_WSADATA ENDS

_sockaddr_in STRUCT
    sin_family WORD ?
    sin_port   WORD ?
    sin_addr   DWORD ?
    sin_zero   BYTE 8 dup (?)
_sockaddr_in ENDS

.data
    WSADATA _WSADATA <>
    sa _sockaddr_in <>
    ip DWORD 2E01A8C0h; 192.168.1.46
    port WORD 5C11h ; port 4444

.code

Start Proc
    AND rsp,-16
    SUB rsp,28h

    MOV cx,514
    LEA rdx, WSADATA
    PUSH rdx
    PUSH rcx
    CALL WSAStartup

    MOV ax,port
    MOV sa.sin_port,ax      ;ax is 16 bits wide (WORD)
    MOV eax,ip              ;eax is 32 bits wide (DWORD) 
    MOV sa.sin_addr,eax
    MOV sa.sin_family, 2 ; AF_INET


   


Start ENDP
End


Before the call (at 00007FF732831015):


00007FF732831000 | 48:83E4 F0               | and rsp,FFFFFFFFFFFFFFF0                |
00007FF732831004 | 48:83EC 28               | sub rsp,28                              |
00007FF732831008 | 66:B9 0202               | mov cx,202                              |
00007FF73283100C | 48:8D15 ED1F0000         | lea rdx,qword ptr ds:[7FF732833000]     |
00007FF732831013 | 52                       | push rdx                                |
00007FF732831014 | 51                       | push rcx                                |
00007FF732831015 | E8 23000000              | call <JMP.&WSAStartup>             |
00007FF73283101A | 66:8B05 85210000         | mov ax,word ptr ds:[7FF7328331A6]       |
00007FF732831021 | 66:8905 6C210000         | mov word ptr ds:[7FF732833194],ax       |
00007FF732831028 | 8B05 74210000            | mov eax,dword ptr ds:[7FF7328331A2]     |
00007FF73283102E | 8905 62210000            | mov dword ptr ds:[7FF732833196],eax     |
00007FF732831034 | 66:C705 55210000 0200    | mov word ptr ds:[7FF732833192],2        |
00007FF73283103D | FF25 BD0F0000            | jmp qword ptr ds:[<Ordinal#115>]        |


Here is the state of my registers :

RAX : 00007FF732831000     <revshell.OptionalHeader.AddressOfEntryPoint>
RBX : 0000000000000000
RCX : 000000A06B5D0202
RDX : 00007FF732833000     /my WSADATA struct/
RBP : 0000000000000000
RSP : 000000A06B3FFA78
RSI : 0000000000000000
RDI : 0000000000000000
R8  : 000000A06B5D5000
R9  : 0000000000000000
R10 : 00007FFB3DF2D150     kernel32.00007FFB3DF2D150
R11 : 0000000000000000
R12 : 0000000000000000
R13 : 0000000000000000
R14 : 0000000000000000
R15 : 0000000000000000
RIP : 00007FF732831015     
RFLAGS : 0000000000000216   

Does anyone have any ideas whe i fed up?

jj2007

You have more chances to get help if you zip your *.asm, *.exe and *.rc files (hopefully full of comments) and attach it here.

phyisio

Ah yes, i wasnt sure how to go about sharing my code. Here is a zip with the .asm and a batch file i use for assembling and linking the libs, you can call with ./make64.bat and then pass in the file name without extension. (I am a beginner with masm , is there a better way of building?). Also maybe check thta the pathst o the libs in the builderr exist on your machine.

Sorry if this is not the right way to ask questions, ill take any feedback

zedd151

For 64 bit assembly, it uses a different calling convention. The first 4 arguments are loaded into registers, not pushed onto the stack. This may help...
https://masm32.com/board/index.php?topic=6177.0


I am not a 64 bit programmer but do know that at least. I mainly work in x86 assembly.
Perhaps peruse the forum looking at others examples in 64 bit before just jumping right in. Mikl__ has some nice tutorials for coding with masm64...

https://masm32.com/board/index.php?board=54.0


And this may be of interest also: The Masm64 SDK

phyisio

Indeed i am passing the arguments to WSAStartup into the rcx and rdx registers, I just decided to push them to the stack later when debugging, to see if it would maybe resolve my problem, but this doesnt seem to change much...

zedd151

Quote from: phyisio on July 04, 2023, 10:56:46 PM
Indeed i am passing the arguments to WSAStartup into the rcx and rdx registers, I just decided to push them to the stack later when debugging, to see if it would maybe resolve my problem, but this doesnt seem to change much...
Ah okay. Lets wait and see what one of the more experienced members here (with 64 bit code) can do to help with debugging...

jj2007

I made a quick test with this source:

include \Masm32\MasmBasic\Res\JBasic.inc ; builds in 32- or 64-bit mode with ML64 & AsmC ##
usedeb=1 ; 1=use the deb macro
.DATA?
align 16
wsadata WSADATA <>
sockad sockaddr_in <>
.DATA
ip DWORD 2E01A8C0h ; 192.168.1.46 little enddian
port WORD 5C11h ; port 4444 little endian also
Init ; OPT_64 1 ; put 0 for 32 bit, 1 for 64 bit assembly
  Cls 8
  PrintLine Chr$("This program was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format.")
  jinvoke WSAStartup, 514, addr wsadata
  deb 4, "WSAStartup results", eax, wsadata.wVersion, wsadata.wHighVersion, wsadata.iMaxSockets, wsadata.iMaxUdpDg, wsadata.szDescription, wsadata.lpVendorInfo
    MOV ax, port
    MOV sockad.sin_port, ax      ;ax is 16 bits wide (WORD)
    MOV eax, ip              ;eax is 32 bits wide (DWORD) 
    MOV sockad.sin_addr, eax
    MOV sockad.sin_family, 2 ; AF_INET 
EndOfCode


Output:
This program was assembled with ml64 in 64-bit format.
WSAStartup results
eax     0
wsadata.wVersion        514
wsadata.wHighVersion    514
wsadata.iMaxSockets     0
wsadata.iMaxUdpDg       0
wsadata.szDescription   0
wsadata.lpVendorInfo    0


So it works in principle, somehow. Underwhelming, though.

phyisio

Thank you for your reply jj. From what I understand you guys all use custom builders and macros? I have only ever use ml64.exe with default parameters, justl inking my libs so im a bit confused by your jinvoke ,deb etc. Anyways i dont think that changes much for my understanding of your reply.

What I see is that you use SBYTE ans SIZE_P in the WSDATA structure instead of my QWORD and BYTE. Is this where  i made an error?
Other than that your code looks similar to mine, so i dont understand why when stepping through my program in x64dbg, at the moment WSAStartup calls a Heap Alloc i get an access violation.

zedd151

Have you tried GlobalAlloc?? I have never had any issues iirc using it.

jj2007

Quote from: phyisio on July 05, 2023, 12:50:17 AM
Thank you for your reply jj. From what I understand you guys all use custom builders and macros? I have only ever use ml64.exe with default parameters, justl inking my libs so im a bit confused by your jinvoke ,deb etc. Anyways i dont think that changes much for my understanding of your reply.

What I see is that you use SBYTE ans SIZE_P in the WSDATA structure instead of my QWORD and BYTE. Is this where  i made an error?
Other than that your code looks similar to mine, so i dont understand why when stepping through my program in x64dbg, at the moment WSAStartup calls a Heap Alloc i get an access violation.

Using your code with minor modifications, see attachment, it works fine.

And yes, I use custom macros: "jinvoke" is my Masm64 equivalent of Masm32 invoke. It is a pretty complex JBasic macro (counts and checks arguments...), but nobody else uses it; so when you see that, consider it pseudo code.

We have at least three competing approaches to Masm64 in this forum alone. Sooner or later, we'll have to sort it out ;-)

phyisio

Thanks, i see. I think stepping through WSAStartup in a debugger for 2 hours might have been the problem from the start.
I will try to setup my env and use your deb macro to check if api call is really working.

Caché GB

Hi phyisio, welcome.

Start Proc

           push  rbp        ; SAVE the stack
            mov  rbp, rsp
            sub  rsp, 28h  ; FIRST shadow stack
            and  rsp,-10h  ; THEN align


          YOUR CODE HERE AND YOU WILL NEVER EVER USE PUSH - POP IN IT, EVER (as a beginner)


            mov  rsp, rbp   ; PUT the "stack-back-Jack"
            pop  rbp


Start endp

Hope this helps.
Caché GB's 1 and 0-nly language:MASM

phyisio

Thank you cachegb , that is a much cleaner way to init my stack. Hwever im pretty sure ill need to push when im calling api functions wit hmore than 4 parameters no? Anywaysthats what i plan on doing....

Caché GB

#13
When you align the stack rsp will hold an address (value in hex) that ends with a 0 (Least Significant Hex "Digit" = 0).
If you use "push" one time, the sack will be unaligned i.e. rsp's LSH = 8. So you just use "push" again, right? That will
make rsp's LSH = 0. Now the stack is alinged again. Yes, but now you have another problem. Any arguments for a call you
have  place on the stack for perms 5 and above will now be moved two perm places to the right. So perm5 becomes perm7
and perm6 moves to (becomes) perm8 and so on. Just write rcx, rdx, r8 and r9 straight to the shadow (spill) space if you
want to watch them.

            mov  qword ptr[rsp+18h], r9
            mov  qword ptr[rsp+10h], r8
            mov  qword ptr[rsp+8h], rdx
            mov  qword ptr[rsp+0h], rcx

Here is an example of how to set the stack up for API calls

            add  rsp, -68h
            and  rsp, -10h


             call  GetDesktopWindow
            mov  qword ptr[rsp+40h], rax

            mov  qword ptr[rsp+58h], null
            mov  rdx, hinstance
            mov  qword ptr[rsp+50h], rdx
            mov  qword ptr[rsp+48h], null

            xor  rdx, rdx
            mov  edx, WindowRect.bottom
            mov  qword ptr[rsp+38h], rdx
            mov  edx, WindowRect.right
            mov  qword ptr[rsp+30h], rdx
            mov  edx, WindowRect.top
            mov  qword ptr[rsp+28h], rdx
            mov  edx, WindowRect.left
            mov  qword ptr[rsp+20h], rdx

            mov   r9, (WS_POPUP OR WS_SYSMENU) ; WS_OVERLAPPEDWINDOW
            mov   r8, offset TitleName
            mov  rdx, offset ClassName
            mov  ecx, WS_EX_APPWINDOW

            mov  qword ptr[rsp+18h], r9   ; only for debuggin
            mov  qword ptr[rsp+10h], r8   ;
            mov  qword ptr[rsp+8h], rdx   ;
            mov  qword ptr[rsp+0h], rcx   ;

           call  CreateWindowEx

Note this very well:
If a function that you make (write) has one or more parameters like this

SomeFunction proc par1:qword

OR if your function has at least one LOCAL variable like so

SomeFunction proc

    local SplitHairs:dword


A stact FRAME will be automaticly created. i.e

           push  rbp         <- STACK FRAME start
            mov  rbp, rsp

    code here

            mov  rsp, rbp
            pop  rbp        <- STACK FRAME end  ( leave = mov  rsp, rbp + pop  rbp )
            ret

Note 

If a function that you make (write) has no parameters and no local, no STACK FRAME will be created.
You will have make one yourself.

Remember: if you do not save the stack pointer before aligning it (rsp), you will not know how to restore
it and you will lose the caller's address on the stack and the callee will return anywhere but home.

Have Fun.
Caché GB
Caché GB's 1 and 0-nly language:MASM

phyisio

Wow i see thank you. I had seen how c compilers do this constitently when creating functions. So since i was not creating a stack frame properly, the function could never return to me?