Hi guys, how r u? I need your help. I am trying to write a program in gnu assembler in which I need to use the "wget" function.  I think that its library in c language is: #include <stdio.h>, so I tried this in my code:

.include stdio.h
.section .data
.section .text
.globl _start
_start:
      call wget
      movl $1, %eax
      movl $0, %ebx
int $0x80

obviously, it returns to me this error

iplog.s: Assembler messages:
iplog.s:1: Error: missing string


Any ideas?
thanks in advance!
Posted on 2011-09-29 15:08:24 by massem
wget is a linux program that you can execute from the shell.  Are you trying to call it from your source???
Posted on 2011-09-29 18:34:59 by p1ranha
Hi Marce,

I don't think wget is a "function" in a C library that you could "call" like that. I could be wrong. As P1ranha says, it's an executable. You could execute it from your program with sys_execve. That doesn't return, so if you wanted to have your program keep running after wget exited, you'd have to sys_fork first, and then execve wget in the "child". Probably better off to execve bash (or other shell), giving wget on the command line to bash. The C library provides system() that would do that.

Or you could "do it yourself" with socket(), connect(), send(), revc(), etc. If you want to do that with sys_calls, there's only one - sys_socketcall - and the various "commands" go in %ebx (pointer to an arguments structure in %ecx)...

You can get rid of the immediate "missing string" error by putting quotes around "stdio.h"... but then it's "not found". There are several versions of "stdio.h". "/usr/include/stdio.h" is apparently not the right one, as it generates a whole pantload of errors. I haven't tried anything beyond that, 'cause I'm not sure that "stdio.h" is what you want anyway...

I do have a "wget-like" program, written by Nathan Baker, using P1ranha's NASMX package(!). It is for Windows, and uses Windows APIs, but I've got a "fakeapi.asm" which I assemble to "fakeapi.o" and link against Nathan's Windows program, allowing it to run in Linux. Pretty cool... as far as it goes. I don't have a "sys_calls only" equivalent to gethostbyname(), so the IP has to be hard-coded in... which limits its usefulness considerably! :(

There's a "wget" in Konstantin's "asmutils" package, too. None of this is in (G)as syntax, but could be "translated" without "too" much trouble.

Easiest thing might be to run "wget" from the command line, and then process the resulting file(s) with your asm program. Depends on what you're trying to do...

In the more general case of calling C libraries from (G)as... we might be able to come up with an example...

Glad to see you're still doing assembly language!

Best,
Frank

Posted on 2011-09-30 08:02:50 by fbkotler
Frank, first of all, i'm not doing assembly language, I am struggling with it! But, to be honest, I love it! it's so hard that I love it! it's so low level that I love it. I know it does not have any sense haah.
My idea of learning this language is developing several little programs. This one has the objective of checking computer's ip in www.whatismyip.com and save the new ip in some file called "iplog". It would be like carrying out an  "ip log".
Well, your answer was very complete and now you cleared me up the idea. What do you think if I try to solve that with sockets...? Will be very difficult? I have developed socket with c once, but I think I have to revise the theory. You named "sys_socketcall ".. is there any documentation that you can recommend me? (meanwhile I'm searching on the Internet).
About the other suggestions, I am trying to learn GnuAssembler in Linux obviously.
well, thank you so much for your answer,
thank P1ranha as well !

Best,
Marce
Posted on 2011-09-30 13:20:22 by massem
Ahhh... documentation... For an overview of what we're trying to do, "Beej's Guide to Network Programming" is good...

http://beej.us/guide/bgnet/

... not really directed at assembly language...

To get more specific, you could do "man 2 socketcall". That doesn't really tell us much. "man 2 socket", man 2 connect", etc. give more information. Not really aimed at asm either, of course...

I'm still at the earliest stages of figuring out what we want to do. If I use the "regular wget":

wget www.whatsmyip.com

I end up with "index.html", which includes the IP we're looking for... and a lot of other stuff which isn't really helpful. Their page mentions another page for "automation":
http://automation.whatismyip.com/n09230945.asp
When I try "wget" on that, I get "ERROR 403: Forbidden". If I just "click on it", I get my IP without any surrounding cruft. I think that page may be "interesting", but I'm not sure how we want to use it...

The general idea, I think, will be sys_socket (or socket() if you like C libraries), sys_connect (or connect()). At this point, we'll need to know the IP for whatismyip.com or their automation page. gethostbyname() should do it. What I usually do is "ping thename" and copy down the "dotted quad" that it tells me. :) The actual parameter  wants to be bigendian(!). Then we may need to send something - sys_socketcall with "send" as an argument, or just sys_write will work. Or maybe, if we hit that "automation" page, it'll send what we want without asking (we should be so lucky), and we can just "recv" (sys_socketcall with "recv" in ebx) or sys_read... Have to try it to see what happens...

I haven't written any code yet. If I can stay "focused", I will. I'll be doing it in Nasm, probably - first, to get it working, at least. Then I'll "translate" to (G)as - "objdump -d myprog" presents AT&T syntax, which will help...

I don't think it'll be too difficult, but I'm short of ambition lately (I've always been short of ambition, but it's getting worse!), so don't wait for me! Try out anything you can think of!

Later,
Frank

Posted on 2011-10-01 07:20:12 by fbkotler
Frank, thank you for the documentation!!!
Regarding to:
I end up with "index.html", which includes the IP we're looking for... and a lot of other stuff which isn't really helpful. Their page mentions another page for "automation":
http://automation.whatismyip.com/n09230945.asp

yes I knew that! I realised yesterday haha
The general idea, I think, will be sys_socket (or socket() if you like C libraries), sys_connect (or connect())

I did that, without libraries and with syscalls  :)


movl $2,(%esp) #af_inet
movl $1,4(%esp) #sock-stream
movl $6,8(%esp) #ipprotocp
movl $102,%eax #socketcall
movl $1,%ebx  #socketcall_socket
movl %esp,%ecx
int  $0x80

Now, I'm trying to figure out the "connect" function.  We have int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen). I have to "translate" the parameters  into assembly.... (a challenge for me). After this, I'm going to follow your recommendations:
gethostbyname() should do it. What I usually do is "ping thename" and copy down the "dotted quad" that it tells me. :) The actual parameter  wants to be bigendian(!). Then we may need to send something - sys_socketcall with "send" as an argument, or just sys_write will work. Or maybe, if we hit that "automation" page, it'll send what we want without asking (we should be so lucky), and we can just "recv" (sys_socketcall with "recv" in ebx) or sys_read... Have to try it to see what happens...


Thank u so much!!!!! ;)

p.s: I'm reading tcp/ip sockets in c second edition practical guide for programmers by Morgan Kaufman
Posted on 2011-10-01 18:47:39 by massem
Good start! I've got something similar - I've got 0 where you've got 6 - IPv4 vs IPv6, I suspect(?). Trying a similar idea with "connect" - arguments on the stack. I'm getting a plausible descriptor from "socket" and 0 from "connect", but "broken pipe" if I try to read/write. Just woke up from a nap realizing, "Wait a minute, 'port 80' is decimal!" I've been using 80 hex. :( Duh!

I really may have to RTFM on this. (it puts me to sleep, but if I can't stay awake anyway, might as well...) :)

Coffee first, then I'll get back into it...

Best,
Frank

Posted on 2011-10-02 00:09:17 by fbkotler
Hi Frank, yes I've got 6,  I'm using IPv4.  I have searched on the Internet some examples about "connect" function and I have some doubts.  This is the code:


movl $102 %eax  #socketcall
movw $2, 12(%esp) #af_inet
movw $80, 14(%esp) #port
movl $0x48e959c7, 16(%esp) # ip
movl %eax, (%esp) #fd
...
..

The questions are:
why do we move only a word in af_inet and port? I remember that in "socketcall function" I did that:

  movl $2,(%esp) #af_inet

I moved a double word. I would like to understand in which occasion do we have to send 32 bits or  16 bits.

Besides I really don't know how can I calculate the size of the sock address. In the example I could see that

leal    12(%esp),%ebx
movl    %ebx,0x4(%esp)

I follow the code to understand what it was looking for in 12(%esp).

movw $2, 12(%esp)#af_inet

It was looking for the af_inet. So, I concluded that it calculates the size through the address family, IPv4.  However, I don't think that this represents the size  the sock address at all.
what's your opinion?
Thanx in advance!
try italian coffee! ;) it's the best
Posted on 2011-10-02 19:13:17 by massem
I should have had the Italian coffee! Instant with a bit of cocoa-mix, a spinkle of cinnamon, hot water from the tap, is quick, but didn't seem to do the trick. Changing "port" to 80 decimal didn't help. What I actually did was:

push 25000h

Supposed to be a word af_inet and a word (big-endian) port. Still got "broken pipe". So I backed up to something a little less "minimal" and used a static structure...

struc sockaddr_in
    .sin_family resw 1
    .sin_port resw 1
    .sin_addr resd 1
    .sin_zero resb 8
endstruc

That's Nasm syntax, but I think you can see that "family" and "port" are words... and then there's some padding at the end, which makes the "size" 16 bytes. I think that's what we want to pass to "connect". It's supposed to be (the "original" structure) in "sys/socket.h" (which includes "bits/socket.h") but I can't find anything just like that...

I didn't actually use the Nasm "struc", since I don't know how to translate it to (G)as. Here's my code, so far. Note that this DOES NOT WORK:

global _start

; Convert numbers (constants!) to network byte order
%define hton(x) ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >>  8) | ((x & 0x0000FF00) <<  8) | ((x & 0x000000FF) << 24)
%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)


section .data
    iptext db "72.233.89.198", 0 ; www.whatismyip.com
;    iptext db "198.89.233.72", 0 ; automation.whatismyip.com
    iplittle dd 48E959C6h
    ipbig dd 0C659E948h
;    ipbig dd 48E959C6h

; copied from Nathan's (working) program
    msg db"GET /index.html HTTP/1.1", 13, 10
        db "Host: www.whatismyip.com", 13, 10
db "Connection: close", 13, 10
db "User-Agent: assembly language", 13, 10
    msg_len equ $ - msg

sa:
    dw 2 ; family
    dw htons (80) ; port (big endian)
    dd 0C659E948h ; address (big-endian)
    dd 0, 0 ; zero
sa_size equ $ - sa

; first of these wants to be socket descriptor
; we fill it in later...
connect_args dd 0, sa, sa_size

section .bss
%define BUFSIZ 80h
    buf resb BUFSIZ
    sock_fd resd 1

section .text
_start:
    nop
; socket
    push 0
    push 1
    push 2
    mov ecx, esp
    mov ebx, 1
    mov eax, 102
    int 80h
    add esp, 12
    test eax, eax
    js exit
    mov , eax
    mov , eax
   
; connect
    mov ecx, connect_args
    mov ebx, 3 ; connect
    mov eax, 102
    int 80h
    add esp, 28
    test eax, eax
    js exit

; write
    mov edx, msg_len
    mov ecx, msg
    mov ebx,
    mov eax, 4
    int 80h
    test eax, eax
    js exit

; read
    mov edx, BUFSIZ
    mov ecx, buf
    mov ebx,
    mov eax, 3
    int 80h
    test eax, eax
    js exit

; write to stdout
    mov edx, eax ; length from read
    mov ecx, buf
    mov ebx, 1
    mov eax, 4
    int 80h
   
exit:
    mov ebx, eax
    test ebx, ebx
    jns goodexit
    neg ebx
goodexit:
    mov eax, 1
    int 80h


That gets me as far as writing the "GET" message (apparently successfully(?), but the "read" doesn't read anything, just hangs there. Apparently I said something to offend the server...

I don't know what to try next. RTFM, if all else fails, I guess... :)

Best,
Frank

Posted on 2011-10-02 23:07:50 by fbkotler
Copied incorrectly(!) from Nathan's code...

  msg db"GET /index.html HTTP/1.1", 13, 10

Supposed to be a space between "HTTP" and "/". This gets me to "Bad Request". Progress, of a sort...

Best,
Frank

Posted on 2011-10-03 05:14:41 by fbkotler
Hi Frank, I understood everything but in connect() function something seems to be wrong. In eax register i found 0xffffff2. An error. And I don't know what  it means.


.section .data
ErrorMsg: .asciz"socket() failed\n"
.section .text
.globl _start
_start:
      #Creating a reliable, stream socket  TCP
      #parameters
        movl $2, (%esp) #af_inet
        movl $1, 4(%esp) #sock-stream
        movl $6, 8(%esp) #ipprotocp

        movl $102,%eax #socketcall
        movl $1,%ebx  #socketcall_socket
        movl %esp,%ecx #A pointer to the syscall args is stored in %ecx.
        int  $0x80
        cmpl $0, %eax
        jl error

        #Establish a connection to the server
        # int fd, struct sockaddr *uservaddr, int addrlen       
        movl  %eax, (%esp)  #fd
        movw $2, 12(%esp) #af_inet
        movw $80, 14(%esp) #port
        movl $48E959C6, 16(%esp) # ip 72.233.89.198 whatismyip
        movl    $16,8(%esp)  # size
  movl    $102,%eax      #socketcall
movl    $3, %ebx    #socketcall_connect
        movl %esp, %ecx pointer to the syscall args is stored in %ecx.
        int    $0x80
     
        cmpl $0, %eax
          jl error

        jmp endprogram
error:  pushl $ErrorMsg
        call printf
        jmp  endprogram

endprogram: 
        movl $1, %eax
movl $0, %ebx
int $0x80



Debugging I could see that in %eax register there is a  0xffffff2 number. It's a negative number, hence there is a problem. 
I searched on the Internet what  it could be, I did not get nothing.
ANY IDEAS?
Thanx in advance

Posted on 2011-10-06 15:01:38 by massem
I'm fast running out of ideas!

0xfffffff2, according to my half-fast arithmetic, should be -EFAULT ("bad address"). These parameters to "connect" are confusing! We want the address (and length) of this "sockaddr" structure... as a part of the "parameter structure" we put in %ecx. I made the following changes to your code, in order to attempt to do this...

.section .data
ErrorMsg: .asciz"socket() failed\n"
.section .text
.globl _start
_start:
      #Creating a reliable, stream socket  TCP
      #parameters
        movl $2, (%esp) #af_inet
        movl $1, 4(%esp) #sock-stream

# no help either way, here!
#        movl $6, 8(%esp) #ipprotocp
        movl $0, 8(%esp) #ipprotocp

        movl $102,%eax #socketcall
        movl $1,%ebx  #socketcall_socket
        movl %esp,%ecx #A pointer to the syscall args is stored in %ecx.
        int  $0x80
        cmpl $0, %eax
        jl error

        #Establish a connection to the server
        # int fd, struct sockaddr *uservaddr, int addrlen       
        movl  %eax, (%esp)  #fd
        movw $2, 12(%esp) #af_inet
# attempt to do 80, big-endian
        movw $0x5000, 14(%esp) #port
        movl $0x48E959C6, 16(%esp) # ip 72.233.89.198 whatismyip
        movl    $16,8(%esp)  # size
leal 8(%esp), %ecx # <-- addr of sockaddr
movl %ecx, 4(%esp) # <--
  movl    $102,%eax      #socketcall
movl    $3, %ebx    #socketcall_connect
        movl %esp, %ecx # pointer to the syscall args is stored in %ecx.
        int    $0x80
     
        cmpl $0, %eax
          jl error

        jmp endprogram
error:  pushl $ErrorMsg
        call printf
        jmp  endprogram

endprogram: 
        movl $1, %eax
movl $0, %ebx
int $0x80

This changes the error return (in %eax) to 0xffffff9f, which I decrypt as -97 or -EAFNOSUPPORT - "address family not supported by protocol".

I was getting this same error from my code when I was attempting to put all the parameters (the "sockaddr" structure, and the pointer/size to it... plus the fd) on the stack. When I changed this to a "static" sockaddr structure (as shown in the last code I posted above... in Nasm syntax), "connect" returned zero, as I understand it's supposed to do. However, when I attempted to "write" a "request" and "read" back the reply, either the "read" hangs and doesn't get anything, or if I change the "request" I'm writing I "read" back "ERROR 400: Bad Request...".

My "request":

    msg db"GET /index.html HTTP/1.1", 13, 10
        db "Host: www.whatismyip.com", 13, 10
db "Connection: close", 13, 10
db "User-Agent: assembly language", 13, 10
    msg_len equ $ - msg


As nearly as I can get from the RFC (2616? I forget the number), there isn't supposed to be a space in "HTTP(space?)/1.1". Without the space, the "read" hangs, and with the space, "bad request". Dunno what to try next.

I have some code which attempts to put those negative numbers into text (just the comments in errno.h). Sort of like "perror()"? I just cut-and-paste it into my code. I should attempt to assemble it into a freestanding .o file which could be linked with... your code, my code, anything. Haven't done so yet. It might help you with error returns from "connect", but it isn't any help with "bad request"!

I use it in a macro:

int 80h
checkerror "we are here", exit

Where, if there's an error, it prints the text "we are here", then the text from errno.h and jumps to the second parameter - could be "retry" or something instead of "exit"...

I think this code has "promise", but it isn't really "finished" yet. I'll try to post it, in some form, soon(ish). It will/would be a PITA to translate to AT&T syntax, so might not be much help to you.

Other than that... no, I don't have any ideas...

Best,
Frank

Posted on 2011-10-06 17:04:15 by fbkotler
See if this will work for you...

In Nasm, we'd have to declare "extern report_error", but Gas seems to assume that, so just call it.

as -o iplog2.o iplog2.s
ld -o iplog2 iplog2.o rpterror.o

Since we're not calling printf anymore, the rest of the "ld cruft" is no longer required! Ain't that nice? :)

If it doesn't work, give a holler and we'll see if we can sort it out. (warning: unzips to current directory)

Best,
Frank

Attachments:
Posted on 2011-10-06 17:45:51 by fbkotler
The following C code shows how to set up sockaddr prior to successfully calling connect():

  struct sockaddr_in sockAddr;  /* socket address structure */

  sockAddr.sin_family = AF_INET;
  sockAddr.sin_port = htons(nProtocolPort);
  sockAddr.sin_addr.s_addr = inet_addr(szHost);


They key piece is the htons() macro which converts host endianess to network endianess.  If you're writing an app on a PC the host endianess is little endian.  Network endian is big endian.

Also, this is the correct command: GET /index.html HTTP/1.1

Posted on 2011-10-06 20:46:25 by p1ranha
Well... it's a million miles from "calling C libraries in Gas", but here's a NASMX program that works...


; wget-like thingy
; author: Nathan Baker
; written for Windows
; modified for Linux, too: fbk
;
; nasm -f win32 nbget -i path to NASMX\
; link "as usual"
;
; for Linux
; nasm -f elf nbget.asm -i path to NASMX/
; nasm -f elf fakeapi.asm
; ld -o get nbget.o get4lin.o -e main

; swap backslashes to slashes
; I *think* Windows will accept slashes, too(?)

%ifidni __OUTPUT_FORMAT__, elf
%include '/inc/nasmx.inc'
%include '/inc/win32/windows.inc'
%include '/inc/win32/kernel32.inc'
%include '/inc/win32/user32.inc'
%include '/inc/win32/wsock32.inc'

%else
%include 'inc\nasmx.inc'
%include 'inc\win32\windows.inc'
%include 'inc\win32\kernel32.inc'
%include 'inc\win32\user32.inc'
%include 'inc\win32\wsock32.inc'
%endif

entry    demo1

; Convert numbers (constants!) to network byte order
%define hton(x) ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >>  8) | ((x & 0x0000FF00) <<  8) | ((x & 0x000000FF) << 24)
%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)

; Nathan's server
;    urltext db "75.126.1.55", 0
_popip equ 4B7E0137h

POPIP equ hton(_popip)
POPPORT equ htons(80)
BUFFSIZE equ 4096

section .bss
    wsadata resb 398
    hsock resd 1
    resp resb BUFFSIZE
    numb resd 1
    remain resd 1
    realsize resd 1

section .data
pop_sa istruc sockaddr_in
    at sockaddr_in.sin_family, dw 2
    at sockaddr_in.sin_port, dw POPPORT
    at sockaddr_in.sin_addr, dd POPIP
    at sockaddr_in.sin_zero, dd 0, 0
iend

msg db "GET / HTTP/1.1", 13, 10
    db "Host: clax.inspiretomorrow.net" ,13 ,10
    db "Connection: close", 13, 10
    db "User-Agent: ASM", 13, 10, 13, 10
msg_len equ $ - msg


proc    demo1
xor eax, eax
mov , eax
invoke WSAStartup, 0x101, wsadata
invoke socket, dword 2, dword 1, dword 0
mov , eax
invoke connect, eax, pop_sa, 16
invoke send, , msg, msg_len, 0
mov ecx, BUFFSIZE
mov , ecx
mov ebx, resp
back:
invoke recv, , ebx, , 0
cmp eax, 0
jz cont
mov ebx, resp
add ebx, eax
add , eax
sub , eax
jmp back
cont:
invoke closesocket,
invoke WSACleanup
invoke GetStdHandle, dword -11
invoke WriteFile, eax, dword resp, , dword numb, 0
    invoke    ExitProcess, dword NULL
    ret

endproc


Actually, with the latest version of NASMX-1.0rc1, it throws a couple of errors. Works with an earlier version...

Best,
Frank

Posted on 2011-10-07 01:00:39 by fbkotler
Frank,
Please try again with the official NASMX-1.0 release.
Let me know if you are successful or what errors you receive and I'll look into it further.
Thank you.
Posted on 2011-10-07 06:08:23 by p1ranha
Hi Rob,

line 60 - non-constant argument to TIMES (iend)
line 72 - fatal: (INVOKE: 9) missing locals directive (invoke WSAstartup...)

Same as rc1, FWIW. I don't know whether the errors are in the source, or in one of the include files - I suspect the former, the source "looks okay" to me... but I'm not very familiar with NASMX...

As I think you know, I prefer "very low level" asm myself, but I think NASMX is a "good idea... if you wanna do it that way". If I get hit with an unexpected stroke of ambition, I'll contribute something to the Linux branch.

One of these days, I've gotta get organized! :)

Best,
Frank

P.S. I suppose I should attach that "fakeapi.asm" in case anyone wants it...

P.P.S. This may deserve a new topic, if we're going to persue it...

Attachments:
Posted on 2011-10-07 09:41:06 by fbkotler
This one's easy: a proc always requires a locals macro to immediately follow.


proc demo1
locals none
  .
  . your code
  .
endproc


The invoke macro fatals if locals is not specified since it's locals job to ensure the procedure stack frame prologue is set up properly.  It has to be done this way as NASMX has to work within the Nasm macro capabilities while accounting for all calling conventions on all supported operating systems.

Posted on 2011-10-07 13:00:08 by p1ranha
Okay, that fixes that one, thanks!

I've still got a problem with "iend". I thought to try it with "-f win32" to see if that made any difference. Of course, that (re)enabled backslashes, so it wouldn't open the include file(s). Commented out that cruft (can you confirm that Windows still copes with slashes?), and another error cropped up. Probably a typo on my part, that one.

Any insight into the "iend" problem? As expected, adding the "-e" switch doesn't help much, but indicates a possible problem at line 358-360 - size_t not (yet) defined(?). I think this is probably an artifact of the "-e" switch only doing one pass(?)...

Thanks for your help with this!

Best,
Frank
Here's the "current" version, just for reference:

; wget-like thingy
; author; Nathan Baker
; written for Windows
; modified for Linux, too: fbk
;
; nasm -f win32 nbget -i path to NASMX\
; link "as usual"
;
; for Linux
; nasm -f elf nbget.asm -i path to NASMX/
; nasm -f elf fakeapi.asm
; ld -o get nbget.o get4lin.o -e main

; swap backslashes to slashes
; I *think* Windows will accept shashes, too(?)

; %ifidni __OUTPUT_FORMAT__, elf
%include '/inc/nasmx.inc'
%include '/inc/win32/windows.inc'
%include '/inc/win32/kernel32.inc'
%include '/inc/win32/user32.inc'
%include '/inc/win32/wsock32.inc'

;%else
;%include 'inc\nasmx.inc'
;%include 'inc\win32\windows.inc'
;%include 'inc\win32\kernel32.inc'
;%include 'inc\win32\user32.inc'
;%include 'inc\win32\wsock32.inc'
;%endif

entry    demo1

; Convert numbers (constants!) to network byte order
%define hton(x) ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >>  8) | ((x & 0x0000FF00) <<  8) | ((x & 0x000000FF) << 24)
%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)

; Nathan's server
;    urltext db "75.126.1.55", 0
_popip equ 4B7E0137h

POPIP equ hton(_popip)
POPPORT equ htons(80)
BUFFSIZE equ 4096

section .bss
    wsadata resb 398
    hsock resd 1
    resp resb BUFFSIZE
    numb resd 1
    remain resd 1
    realsize resd 1

section .data
pop_sa istruc sockaddr_in
    at sockaddr_in.sin_family, dw 2
    at sockaddr_in.sin_port, dw POPPORT
    at sockaddr_in.sin_addr, dd POPIP
    at sockaddr_in.sin_zero, dd 0, 0
iend

msg db "GET / HTTP/1.1", 13, 10
    db "Host: clax.inspiretomorrow.net" ,13 ,10
    db "Connection: close", 13, 10
    db "User-Agent: ASM", 13, 10, 13, 10
msg_len equ $ - msg


proc    demo1
locals none
xor eax, eax
mov , eax
invoke WSAStartup, 0x101, wsadata
invoke socket, dword 2, dword 1, dword 0
mov , eax
invoke connect, eax, pop_sa, 16
invoke send, , msg, msg_len, 0
mov ecx, BUFFSIZE
mov , ecx
mov ebx, resp
back:
invoke recv, , ebx, , 0
cmp eax, 0
jz cont
mov ebx, resp
add ebx, eax
add , eax
sub , eax
jmp back
cont:
invoke closesocket,
invoke WSACleanup
invoke GetStdHandle, dword -11
invoke WriteFile, eax, dword resp, , dword numb, 0
    invoke    ExitProcess, dword NULL
    ret

endproc


Posted on 2011-10-07 14:04:56 by fbkotler
Here's modified source that assembles without error.
Please see my comments marked as RN:
Note that I did not have time to debug this,
I only nasmxified it :)


; wget-like thingy
; author; Nathan Baker
; written for Windows
; modified for Linux, too: fbk
;
; nasm -f win32 nbget -i path to NASMX\
; link "as usual"
;
; for Linux
; nasm -f elf nbget.asm -i path to NASMX/
; nasm -f elf fakeapi.asm
; ld -o get nbget.o get4lin.o -e main

; swap backslashes to slashes
; I *think* Windows will accept shashes, too(?)

; RN: Nasm accepts either for %include in your source
;    at least with recent versions of Nasm.  However,
;    anything that reads/writes to disk must use the
;    backslash in the path.  It's best to simply
;    always follow the host convention.

; RN: assuming you've set environment:
;    Windows: set NASMENV=-IC:\path\to\nasmx\inc\
;    Linux: export NASMENV=-I/path/to/nasm/inc/

%ifidni __OUTPUT_FORMAT__, elf

%include 'nasmx.inc'
%include 'win32/windows.inc'
%include 'win32/kernel32.inc'
%include 'win32/user32.inc'
%include 'win32/winsock.inc'
%include 'win32/wsock32.inc'

%else

%include 'nasmx.inc'
%include 'win32\windows.inc'
%include 'win32\kernel32.inc'
%include 'win32\user32.inc'
;
; RN: There is an easily corrected bug in winsock.inc
;    find the line containing
;        typedef SOCKET, size_t
;    and replace with
;        %xdefine SOCKET size_t
;
%include 'win32\winsock.inc'
%include 'win32\wsock32.inc'
%endif

entry    demo1

;
; RN: Windows exposes htons as a function,
;    thus to use your own hton macros you must
;    comment out the htonl and htons imports in wsock32.inc
;
; Convert numbers (constants!) to network byte order
%define hton(x) ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >>  8) | ((x & 0x0000FF00) <<  8) | ((x & 0x000000FF) << 24)
%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)

; Nathan's server
;    urltext db "75.126.1.55", 0
_popip equ 4B7E0137h

POPIP equ hton(_popip)
POPPORT equ htons(80)
BUFFSIZE equ 4096

section .bss
    wsadata resb 398
    hsock resd 1
    resp resb BUFFSIZE
    numb resd 1
    remain resd 1
    realsize resd 1

section .data
;pop_sa istruc sockaddr_in
;    at sockaddr_in.sin_family, dw 2
;    at sockaddr_in.sin_port, dw POPPORT
;    at sockaddr_in.sin_addr, dd POPIP
;    at sockaddr_in.sin_zero, dd 0, 0
;iend

; RN: Yes, it's ugly but it permits access
;    to nested strucs and unions
NASMX_ISTRUC pop_sa, SOCKADDR_IN
    NASMX_AT sin_family, AF_INET
    NASMX_AT sin_port,  POPPORT
    NASMX_ISTRUC sin_addr, IN_ADDR
        NASMX_AT S_un.S_addr, POPIP
    NASMX_IENDSTRUC
NASMX_IENDSTRUC

msg db "GET / HTTP/1.1", 13, 10
    db "Host: clax.inspiretomorrow.net" ,13 ,10
    db "Connection: close", 13, 10
    db "User-Agent: ASM", 13, 10, 13, 10
msg_len equ $ - msg



proc  demo1
locals none
xor eax, eax
mov dword , eax
invoke WSAStartup, 0x101, wsadata
invoke socket, 2, 1, 0
mov size_t , eax
invoke connect, eax, pop_sa, 16
invoke send, size_t , msg, msg_len, 0
mov ecx, BUFFSIZE
mov dword , ecx
mov ebx, resp
back:
invoke recv, size_t , ebx, dword , 0
cmp eax, 0
jz cont
mov ebx, resp
add ebx, eax
add , eax
sub , eax
jmp back
cont:
invoke closesocket, size_t
invoke WSACleanup
invoke GetStdHandle, dword -11
invoke WriteFile, eax, dword resp, dword , dword numb, 0
    invoke    ExitProcess, dword NULL
endproc


And the makefile I used for a Windows build:
(Note I named the source file above "wgetx.asm")


##### Makefile #####
NAME=wgetx
AS=nasm
AFLAGS=-f win32
#AFLAGS=-f win32 -dUNICODE=1
LD=GoLink
LDFLAGS =/entry _main
LIBS =kernel32.dll user32.dll wsock32.dll

# [ Suffixes ]
# Change the suffixes to match your system environment
O          = .obj
X          = .exe
ASM        = .asm
INC        = .inc
LST        = .lst

# rules
all: $(NAME)$(X)

$(NAME): $(NAME)$(X)

$(NAME)$(X): $(NAME)$(O)
$(LD) $(LDFLAGS) $(NAME)$(O) $(LIBS)

$(NAME)$(O): $(NAME)$(ASM)
$(AS) $(AFLAGS) $(NAME)$(ASM) -o $(NAME)$(O) -l $(NAME)$(LST)

clean:
-del /f *.obj
-del /f *.lst

cleaner:
-del /f *.bak
-del /f *.lst
-del /f *.obj
-del /f *.exe

##### End Makefile #####

Posted on 2011-10-07 21:53:22 by p1ranha