I'm trying to establish an HTTP connection from assembly using the Windows API. The code is the following:
%include "const.asm"
%define u(x) __utf16__(x)
%define w(x) __utf32__(x)
; Externs
extern InternetOpenA
extern GetLastError
section .data
curProc db 0
hInternet dq 0
lpszAgent db "Mozilla/5.0", 0
section .text
global Start
Start:
sub rsp, 8
sub rsp, 32 + 1 * 8
lea rcx, [REL lpszAgent] ; lpszAgentW (WIDE STRING)
mov rdx, 4 ; dwAccessType (DWORD)
mov r8, NULL ; lpszProxy (DWORD)
mov r9, NULL ; pszProxyBypassW (DWORD)
mov dword [rsp + 4 * 8], NULL ; dwFlags (DWORD)
call InternetOpenA
mov [REL hInternet], rax
add rsp, 32 + 1 * 8 ; hInternet parameter
cmp rax, NULL
je error_handler
; Stop
jmp exit
error_handler:
sub rsp, 32
call GetLastError ; Load more error info
add rsp, 32 + 8
ret
exit: ; Graceful shutdowns
xor rax, rax
add rsp, 8
ret
The corresponding Makefile is:
INCLUDES := kernel32.lib user32.lib wininet.lib
.PHONY: all compile link clean
all: build
compile:
@echo "Compiling assembly"
nasm -f win64 main.asm -o main.o
link: compile
@echo "Linking assembly"
polink /ENTRY:Start /SUBSYSTEM:CONSOLE /LIBPATH:C:\lib64 $(INCLUDES) main.o
build: link
clean:
@echo "Cleaning up"
del main.o
When I'm running it, the error code returned is -1073741819
or 0xC0000005
as @selbie pointed out, or also known as Access Violation. I've received segfault for both wininet
and winhttp
while creating the handle. I'm attaching a short C code showing exactly what I would like to do:
(The assembly should not have the prints. It is just in the C source for debug purposes)
#include "windows.h"
#include "wininet.h"
#include <stdio.h>
int main() {
const char *agent = "Mozilla/5.0";
HINTERNET handler = InternetOpenA(agent, INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY, 0, 0, 0);
if (handler) {
return 0;
}
printf("%d", GetLastError());
return 1;
}
Just for clarity, I am compiling for 64-bit Windows. I am also statically linking as seen in the Makefile
.
Cheers
Edit: Code for some debugging:
[BITS 64]
%include "const.asm"
%define u(x) __utf16__(x)
%define w(x) __utf32__(x)
; Externs
extern InternetOpenA
extern GetLastError
extern GetStdHandle
extern WriteFile
section .data
curProc db 0
hInternet dq 0
lpszAgent db "Mozilla/5.0", 0
NtlpBuffer: db 'Hello, World!', 0
NtnNBytesToWrite: dq 0eh
section .text
global Start
Start:
sub rsp, 8
mov rax, rsp
mov rbx, 8
xor rdx, rdx
div rbx
cmp rdx, 0
je main
sub rsp, 32 + 1 * 8
and rsp, -16
lea rcx, [REL lpszAgent] ; lpszAgentW (WIDE STRING)
mov rdx, 4 ; dwAccessType (DWORD)
mov r8, NULL ; lpszProxy (DWORD)
mov r9, NULL ; pszProxyBypassW (DWORD)
mov dword [rsp + 4 * 8], NULL ; dwFlags (DWORD)
call InternetOpenA
mov [REL hInternet], rax
add rsp, 32 + 1 * 8 ; hInternet parameter
cmp rax, NULL
je error_handler
; Stop
jmp exit
error_handler:
sub rsp, 32
call GetLastError ; Load more error info
add rsp, 32 + 8
ret
exit: ; Graceful shutdowns
xor rax, rax
add rsp, 8
ret
main:
sub rsp, 32
mov ecx, -11
call GetStdHandle
mov rcx, rax
lea rdx, [rel NtlpBuffer]
mov r8, [REL NtnNBytesToWrite]
mov r9, NULL
mov qword [rsp + 32], 00h
call WriteFile
add rsp, 32
ExitProgram:
xor eax, eax
add rsp, 8
ret
After hours of trying and failing, a fellow assembly programmer, @sbdswr, from Discord helped me debugging it -- funnily enough without any debugger. The problem indeed lay in my stack pointer handling as @Peter Cordes already pointed out. Here is the full version of the fixed code. Thank you for your help!
BITS 64
%include "const.asm"
%define u(x) __utf16__(x)
%define w(x) __utf32__(x)
; Externs
extern InternetOpenA
extern GetLastError
extern GetStdHandle
extern WriteFile
extern ExitProcess
section .data
curProc db 0
hInternet dq 0
lpszAgent db "Mozilla/5.0", 0
NtlpBuffer: db 'Hello, World!', 0
NtnNBytesToWrite: dq 0eh
section .text
global Start
Start:
push rbp
mov rbp, rsp
sub rsp, 48
lea rcx, [REL lpszAgent] ; lpszAgentW (WIDE STRING)
mov rdx, 4 ; dwAccessType (DWORD)
mov r8, NULL ; lpszProxy (DWORD)
mov r9, NULL ; pszProxyBypassW (DWORD)
mov dword [rsp + 4 * 8], NULL ; dwFlags (DWORD)
call InternetOpenA
mov [REL hInternet], rax ; hInternet parameter
cmp rax, NULL
je error_handler
jmp exit
error_handler:
call GetLastError ; Load more error info
jmp exit
exit:
call print
xor rcx, rcx
call ExitProcess
print:
sub rsp, 40
mov ecx, -11
call GetStdHandle
mov rcx, rax
lea rdx, [rel NtlpBuffer]
mov r8, [REL NtnNBytesToWrite]
mov r9, NULL
mov qword [rsp + 32], 00h
call WriteFile
add rsp, 40
ret