The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: marla on February 16, 2006, 04:14:09 PM

Title: nested loops?
Post by: marla on February 16, 2006, 04:14:09 PM
my professor wanted us to translate code that iterates through ip addresses ... to asm. i am having difficulties using jmp's and loops versus the c style for loop. here is the c code.

<code>
// scan internet
void scanner(void) {
   int a, b, c, d, e;
   for (a = 1; a <= 255; a++) {
      // avoid class A LOCAL networks
      if(a != 10 && a != 127) {
         for (b = 0; b <= 255; b++) {   
            for (c = 0; c <= 255; c++) {
               for (d = 0; d <= 255; d++) {
                  char ip[32];
                  sprintf(ip, "%d.%d.%d.%d", a, b, c,d);
                  for (e = 0; e <= TCP_portsCount; e++) {
                     printf("%s:%i\n", ip, TCP_ports[e]);
                     checkPort(ip, TCP_ports[e]);
                  }
               }
            }
         }
      }
   }
}
</code>

here is my asm code so far. i know that it will not work but i am just trying to get some guidance as to where i should be going.

<code>
; iterate through ip's
   ScanInternet:
      mov  AL, 255
      mov  AH, 255
      mov  BL, 255
      mov  BH, 255

      ip   DB  ""

      mov CX, 255
      count255_1:
         mov CX, 255
         count255_2:
            mov CX, 255
            count255_3:
               mov CX, 255
               count255_4:
                  invoke wsprintf(ip, "%d.%d.%d.%d", AL, AH, BL, BH);
                  call CheckPorts(ip, [TCP_ports + X]);
               loop count255_4
            loop count255_3
         loop count255_2
      loop count255_1
</code>
Title: Re: nested loops?
Post by: Ratch on February 16, 2006, 06:05:28 PM
marla,
     The following should get you started.  As you can see, the loop counters are local variables stored on the stack.  One line as noted does not make sense.  How can "a" be two values at the same time?  The operations in the innermost loop you can code yourself.  Ask if you have any questions.  Ratch


@        EQU     OFFSET

.data?
char byte 32 dup (?)
.data
format1 BYTE '%d.%d.%d.%d',0

.CODE
ScanInt STRUCT
a       DWORD ?
b       DWORD ?
cc      DWORD ?
d       DWORD ?
e       DWORD ?
ScanInt ENDS

SCI      EQU ESP.ScanInt

scanner:
PUSHIT 0,0,0,0,0           ;initialize local variables a,b,c,d,e

.REPEAT
  INC [SCI.a]

  ; avoid class A LOCAL networks
  .IF ([SCI.a]!=10) && ([SCI.a]!=127) ;THIS LINE DOES NOT MAKE SENSE
    .REPEAT
      .REPEAT
        .REPEAT
          INVOKE wsprintf,@ char,@ format1,[SCI.a],[SCI.b],[SCI.cc],[SCI.d]

          .REPEAT
;           printf("%s:%i\n", ip, TCP_ports[e]);
;           checkPort(ip, TCP_ports[e]);
           INC [SCI.e]
          .UNTIL [SCI.e] >= TCP_portsCount+1
         INC [SCI.d]
        .UNTIL [SCI.d] >= 255+1
       INC [SCI.cc]
      .UNTIL [SCI.cc] >= 255+1
     INC [SCI.b]
    .UNTIL [SCI.b] >= 255+1
  .ENDIF
.UNTIL [SCI.a] >= 255

ADD ESP,ScanInt             ;recover local variable space
RET
END
Title: Re: nested loops?
Post by: Tedd on February 16, 2006, 06:22:38 PM
One thing you need to remember is that calls to functions will mess up the values in most of your registers, so it's a good idea to save any register values you want to keep (or use local variables - as in ratch's example.)
You have the same problem with your code - cx is used as a count for each loop, but each loop inside it will change its value. So you'd need to surround each one with a "push ecx" and "pop ecx" (this is 32-bit code?) to make sure you have the correct counter with each loop.
Title: Re: nested loops?
Post by: Tedd on February 16, 2006, 06:26:32 PM
.IF ([SCI.a]!=10) && ([SCI.a]!=127)     ;THIS LINE DOES NOT MAKE SENSE

Yes it does, Ratch :P
(if-not-equal, not if-equal)
Title: Re: nested loops?
Post by: Ratch on February 16, 2006, 07:15:18 PM
Tedd,
     Yer right.  I guess I was thinking of equal too much.  Thanx for the correction.  Ratch
Title: Re: nested loops?
Post by: marla on February 16, 2006, 07:25:05 PM
i appreciate the help from both of you. i removed the equ so that i can learn/understand the code better. i had a few questions, here is my new complete .asm file.




include \MASM32\INCLUDE\windows.inc
include \MASM32\INCLUDE\masm32.inc
include \MASM32\INCLUDE\kernel32.inc

includelib \MASM32\LIB\masm32.lib
includelib \MASM32\LIB\user32.lib
includelib \MASM32\LIB\kernel32.lib

.data?

char BYTE 32 DUP (?)

;-----------------

.data
format1 BYTE '%d.%d.%d.%d',0

;-----------------

.code

ScanInt STRUCT
   a       DWORD ?
   b       DWORD ?
   cc      DWORD ?
   d       DWORD ?
   e       DWORD ?
ScanInt ENDS

scanner:
   PUSHIT 0,0,0,0,0
   .REPEAT
              INC [ESP.ScanInt.a]
              .REPEAT
                 .REPEAT
                    .REPEAT
                       INVOKE wsprintf,OFFSET char,OFFSET format1,[ESP.ScanInt.a],[ESP.ScanInt.b],[ESP.ScanInt.cc],[ESP.ScanInt.d]
       .REPEAT
                           print chr$(char)
                           INC [ESP.ScanInt.e]
                 .UNTIL [ESP.ScanInt.e] >= TCP_portsCount+1
              INC [ESP.ScanInt.d]
            .UNTIL [ESP.ScanInt.d] >= 255+1
        INC [ESP.ScanInt.cc]
      .UNTIL [ESP.ScanInt.cc] >= 255+1
              INC [ESP.ScanInt.b]
              .UNTIL [ESP.ScanInt.b] >= 255+1
           .UNTIL [ESP.ScanInt.a] >= 255

ADD ESP, ScanInt
RET

END


ok:

1: why does "ADD ESP, ScanInt" recover local variables?
2: what does RET do? is that the same as invoke exit_process ?
3: i understand that the masm specific .if .until .repeat etc are just as good as pure asm, but i am trying to learn assembly and not think like C/higher level language: how can i convert this to pure asm?
4: thanks again for the help!
Title: Re: nested loops?
Post by: Ratch on February 16, 2006, 10:39:37 PM
marla,
Quote
1: why does "ADD ESP, ScanInt" recover local variables?

     It recovers the stack space used by the local variables.  Five DWORD zeroes were PUSHed onto the stack.  For each PUSH, ESP is decremented by a DWORD length of 4, for a total of 20 after the 5 PUSH sequence.  Just before the program finishes, 20 is added to ESP to balance the stack to what it was when the program was entered.  ScanInt is the name of the STRUCT, which MASM equates to the STRUCT length of 20, when used in context as an arithmetic constant.  The result is the same as doing 5 POP's, but it is quicker and less code to simple move the ESP by adding to it.

Quote
what does RET do? is that the same as invoke exit_process ?

     Yes, I coded the example as if it were to be CALL'ed or INVOKE'ed.  So the program assumes that there is a return address on the stack which RET removes and jumps to. 

Quote
3: i understand that the masm specific .if .until .repeat etc are just as good as pure asm, but i am trying to learn assembly and not think like C/higher level language: how can i convert this to pure asm?

     You can see what code is generated by the assembly and copy that.  The nice thing about those high level constructs is that you don't have to think of creative local jump labels.  Use the /Sn and /Sg switches when you execute MASM to see what the generated code is from the high level constructions.

Quote
4: thanks again for the help!

     You are welcome.  Ratch


Title: Re: nested loops?
Post by: Tedd on February 17, 2006, 12:51:31 PM
RET is used to RETurn from a function - back to where it was called from. So it's still a good idea to use ExitProcess where you actually mean for the process to end (ret will usually work, but only because windows catches this and calls exitprocess for you.)

Since your code isn't within a function, you could place the scanint variables in the .data? section (just keeps things a little tidier - they still actually go on the stack, but it's cleaned up when you exitprocess.)

It's good that you want to understand how the higher-level constructs work :wink So here's a quick explanation for 'if' - you can probably work the others out for yourself.

.IF (eax == 7)    ;cmp eax,7  ;jne @else
    mov ecx,1     ;mov ecx,1
                  ;jmp @endif
.ELSE             ;@else:
    mov ecx,0     ;mov ecx,0
.ENDIF            ;@endif:


A while-loop (repeat until) would be similar, but with a jump back to the start to make it loop.



And just for fun, here's your code without these constructs (and ExitProcess, etc)

include \MASM32\INCLUDE\windows.inc
include \MASM32\INCLUDE\masm32.inc
include \MASM32\INCLUDE\kernel32.inc

includelib \MASM32\LIB\masm32.lib
includelib \MASM32\LIB\user32.lib
includelib \MASM32\LIB\kernel32.lib

;************************************************************************************************

TCP_portsCount equ 0ffffh

SCANINT STRUCT
   a_      DWORD ?
   b_      DWORD ?
   c_      DWORD ?
   d_      DWORD ?
   e_      DWORD ?
SCANINT ENDS

;************************************************************************************************

.data
format1 BYTE '%d.%d.%d.%d',0

;************************************************************************************************

.data?
scint   SCANINT <?>
char    BYTE 32 DUP (?)

;************************************************************************************************

.code

scanner:
    xor eax,eax         ;eax = 0
    mov [scint.a_],1    ;"0.?.?.?" are invalid, so we start at a=1
    mov [scint.b_],eax
    mov [scint.c_],eax
    mov [scint.d_],eax
    mov [scint.e_],eax

    @loop_a:               ;.REPEAT

;;ip addresses "127.?.?.?" and "10.?.?.?" are reserved - which is why the original had the 'if' to avoid checking them
      @loop_b:                 ;.REPEAT

          @loop_c:                 ;.REPEAT

              @loop_d:                 ;.REPEAT

                    INVOKE wsprintf,OFFSET char,OFFSET format1,[scint.a_],[scint.b_],[scint.c_],[scint.d_]
                  @loop_port:              ;.REPEAT
                    print chr$(char)
                    INC [scint.e_]
                    cmp [scint.e_],TCP_portsCount
                    jle @loop_port         ;.UNTIL ([scint.e_] > TCP_portsCount)

                INC [scint.d_]
                cmp [scint.d_],255
                jle @loop_d            ;.UNTIL ([scint.d_] > 255)

            INC [scint.c_]
            cmp [scint.c_],255
            jle @loop_c            ;.UNTIL ([scint.c_] > 255)

        INC [scint.b_]
        cmp [scint.b_],255
        jle @loop_d            ;.UNTIL ([scint.b_] > 255)

    INC [scint.a_]
    cmp [scint.a_],254     ;;"255.?.?.?" are invalid
    jle @loop_a            ;.UNTIL ([scint.a_] > 254)

    invoke ExitProcess, NULL
END

Title: Re: nested loops?
Post by: marla on February 17, 2006, 05:08:21 PM
thanks again, i have learned enough here to keep busy for a long time, time to get nitty gritty. i wish that my school offered a win32 asm class :/
Title: Re: nested loops?
Post by: zooba on February 18, 2006, 01:32:23 AM
Quote from: Tedd on February 17, 2006, 12:51:31 PM
Since your code isn't within a function, you could place the scanint variables in the .data? section (just keeps things a little tidier - they still actually go on the stack, but it's cleaned up when you exitprocess.)

They don't go on the stack, they have a page allocated by the loader. Check a disassembly, the addresses are hard-coded (at least the offset from the page is) - there's no registers involved as for the stack.

I also don't understand the point in using a structure instead of MASM's local variables:

scanner PROC
    LOCAL a:DWORD, b:DWORD, c:DWORD, ...
   
    ...
   
scanner ENDP


It's a tool which is just as valid and just as high-level as using a structure. :U
Title: Re: nested loops?
Post by: Ratch on February 18, 2006, 02:19:13 AM
zooba,

Quote
They don't go on the stack, they have a page allocated by the loader.

     Right you are.  The .DATA? method suggested by Tedd makes them, in effect, global variables.

Quote
     I also don't understand the point in using a structure instead of MASM's local variables:

     I am responsible for suggesting to marla that he use that method.  That's because I am a PROCless programmer.  I consider PROCs a "red tape" directive that is more trouble than it is worth.  I would be happy to debate the pros and cons of my method.  For background, you might want to review the link below.  Ratch

http://www.masmforum.com/simple/index.php?topic=3783.0
Title: Re: nested loops?
Post by: zooba on February 18, 2006, 02:48:08 AM
Quote from: Ratch on February 18, 2006, 02:19:13 AM
I am responsible for suggesting to marla that he use that method.  That's because I am a PROCless programmer.  I consider PROCs a "red tape" directive that is more trouble than it is worth.  I would be happy to debate the pros and cons of my method.  For background, you might want to review the link below.  Ratch

http://www.masmforum.com/simple/index.php?topic=3783.0


I've read the page you link to. I am happy to debate with you, but in the end it comes down to personal preference anyway :wink . Using a structure as a stack-frame substitute is an advanced process which (IMHO) is not ideal for teaching beginners. :U
Title: Re: nested loops?
Post by: Ratch on February 18, 2006, 03:19:33 AM
zooba,

Quote
Using a structure as a stack-frame substitute is an advanced process which (IMHO) is not ideal for teaching beginners.

     You could be right.  It's hard at times for a experienced user to put oneself into the beginners shoes.   I think it should be up to the  beginner to decide which method he wants to learn and use.  My opinion is that PROC's are another layer of software and complexity that gets between the problem and the programmer.  And sometimes I observe a lot of angst and gnashing of teeth with regard to making PROC's do what the programmer wants.   Does anyone else have a opinion?  Ratch
Title: Re: nested loops?
Post by: Ian_B on February 18, 2006, 02:43:03 PM
I think more than any other language ASM allows programmers to indulge their individual style, whether for good or bad. That's why in a couple of threads recently it seems like there are "too many cooks" trying to show the best way to do something really very simple, making their own assumptions about what the poor newbie really wants or needs...  :bdg   It's no wonder ASM seems confusing!

{EDIT}

As long as code is well-commented, verbosely even, style shouldn't really be that much of an issue to newbies. The important thing is surely explaining the assumptions and the methods clearly.

IanB
Title: Re: nested loops?
Post by: Ratch on February 18, 2006, 03:47:26 PM
Ian_B,
     Thank you for your musings.

Quote
... but the writer was completely convinced that the best way to code procedures (or at least ones as small as these) was to pass all the parameters in registers rather than all the syscall push/pop convention and messing with stack frames, etc.

     Putting all the function parameters into registers is a good way to go if one has the registers to do it, and you don't need to use the parameter registers within the function for other purposes other than reading the values they contain.  If one has to save and restore the registers, then the parameters might as well be sent to the function via stack/memory in the first place.  Unfortunately INTEL type CPU's suffer register 'starvation' , unlike the MOTOROLA 68XXX series.  I use registers to pass parameters whenever I can, but sooner or later one runs out of registers to use.

Quote
I never use stack parameters or frames unless it's absolutely necessary, and because I often have fall-through procs with different start conditions, I use the dangerous "option no-scoped" parameter

     Since I don't use PROC's, my entire program is running as "no-scoped".  No problem, however, because I use global variables where needed, and local variables which are manipulated on the stack.  I too like to fall through on  code that can also be INVOKE'd.

Quote
Even at my stage in the game, I don't think I'd want to play with your proc coding suggestion, Ratch. I'm kinda happy with what I do, and it would add another layer of complexity I don't really need or want when I'm finding it hard enough going to just code in ASM

     I hear you and understand.  My method requires one to be aware of the stack at all times.  In other words, one has to be a stackmaster.  But is it is very flexible.  Sometimes one can PUSH parameters a long way before an INVOKE is encountered, when the parameter first becomes available, so the parameter does not have to be saved somewhere until it is needed.

Quote
Same with all the macro stuff that you guys use all the time

     MACRO's can be useful and misused.  Some MACRO's I've seen are complicated 'works of art' rather than something a programmer would like to use constantly.  Still others do trivial things that might as well be coded directly.  Ratch
Title: Re: nested loops?
Post by: hutch-- on February 18, 2006, 03:59:53 PM
Perhaps these trailing discussions should be posted in another subforum rather than the campus as they are of little value to the majority of people learning a complex language like assembler.
Title: Re: nested loops?
Post by: Ian_B on February 18, 2006, 04:01:42 PM
Can't you just split them off as a separate thread like on most other forums?

IanB
Title: Re: nested loops?
Post by: hutch-- on February 18, 2006, 04:08:15 PM
I actually don't need advice on how to use the forum software. I was more interested in keeping the campus for what it was intended for instead of extended waffle that is of little use to learners.
Title: Re: nested loops?
Post by: Ian_B on February 18, 2006, 05:21:38 PM
That's OK, I've removed the "waffle". I guess as a forum owner myself I was expecting a little more proactive moderation/management rather than being told off like a child.  ::)

Please remove my account.
Title: Re: nested loops?
Post by: marla on February 18, 2006, 10:32:53 PM
when i try and assemble this, i get the error:

Assembling: ips.asm
ips.asm(69) : error A2071: initializer magnitude too large for specified size
chr$(3): Macro Called From
  print(0): Macro Called From
   ips.asm(69): Main Line Code

... any idea why this happens guys?

Title: Re: nested loops?
Post by: Ratch on February 18, 2006, 10:48:20 PM
marla,
     Googling for error A2071 gives the following link. http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B73752
It says that the error is at line 69 of ips.asm.  It tells you that MACRO functions chr$(3) and print(0) were called.  Can't tell much more without the assembly listing, preferably with the MACRO's expanded (.LISTMACROALL).  Ratch
Title: Re: nested loops?
Post by: marla on February 18, 2006, 11:09:10 PM
what does that mean, the macros expanded? and how do i do that .. sorry noob. :/  :tdown
Title: Re: nested loops?
Post by: zooba on February 18, 2006, 11:09:47 PM
Reading upwards:

At line 69 of ips.asm, 'print' was called
At line 0 of print, 'chr$' was called
At line 3 of chr$, the initializer was too large for the specified size

Looking at line 3 of chr$ (txtname db any_text,0) I would guess you're passing an integer directly (ie, chr$(1234) ) where the integer is too large to fit within a byte. However, without seeing the original code (specifically, line 69 of ips.asm) there isn't much we can do to help.

Cheers,

Zooba :U
Title: Re: nested loops?
Post by: marla on February 18, 2006, 11:21:55 PM
ok, here is the code, but isnt an ip address a 32 bit number? then shouldnt format and char both be DWORD 's veruss BYTE 's ?

here is my code:




;-----------------
; ips.asm
;-----------------

.486
.model flat, stdcall
option casemap :none

include C:\MASM32\INCLUDE\windows.inc
      include C:\masm32\macros\macros.asm
include C:\MASM32\INCLUDE\masm32.inc
      include C:\MASM32\INCLUDE\user32.inc
include C:\MASM32\INCLUDE\kernel32.inc
include C:\MASM32\INCLUDE\gdi32.inc

includelib C:\MASM32\LIB\masm32.lib
includelib C:\MASM32\LIB\user32.lib
includelib C:\MASM32\LIB\kernel32.lib
includelib C:\MASM32\LIB\gdi32.lib

;-----------------

TCP_portsCount equ 0ffffh

SCANINT STRUCT
   a_      DWORD ?
   b_      DWORD ?
   c_      DWORD ?
   d_      DWORD ?
   e_      DWORD ?
SCANINT ENDS

;-----------------

.data
format1 BYTE '%d.%d.%d.%d',0

;-----------------

.data?
scint   SCANINT <?>
char    BYTE 32 DUP (?)

;-----------------

.code

scanner:
xor eax,eax
mov [scint.a_], 1
mov [scint.b_], eax
mov [scint.c_], eax
mov [scint.d_], eax
mov [scint.e_], eax

    @loop_a:
      @loop_b:
          @loop_c:
              @loop_d:
                  INVOKE wsprintf,OFFSET char,OFFSET format1,[scint.a_],[scint.b_],[scint.c_],[scint.d_]
                  @loop_port:
                  print chr$(char)
                  INC [scint.e_]
                    cmp [scint.e_],TCP_portsCount
                    jle @loop_port
                INC [scint.d_]
                cmp [scint.d_], 255
                jle @loop_d
            INC [scint.c_]
            cmp [scint.c_], 255
            jle @loop_c
        INC [scint.b_]
        cmp [scint.b_], 255
        jle @loop_d
    INC [scint.a_]
    cmp [scint.a_], 254
    jle @loop_a

    invoke ExitProcess, NULL

end
;-----------------
;
;
;
;
Title: Re: nested loops?
Post by: zooba on February 18, 2006, 11:36:00 PM
'format' and 'char' are strings - ASCII strings are simply consecutive bytes. 'char' is actually an uninitialised string of length 32 (hence 32 DUP (?)).

The problem is that what you are actually passing to chr$ is the address of char:

      chr$ MACRO any_text:VARARG
        LOCAL txtname
        .data
          txtname db any_text,0
        .code
        EXITM <OFFSET txtname>
      ENDM


We now substitute 'char' for 'any_text', in accordance with your line of code:

LOCAL txtname
        .data
          txtname db char,0
        .code


In this context, the assembler attempts to use the address of char, since it has no way of knowing it's contents. A 32-bit address won't fit into a single byte, hence the error.

Not being familiar with the MASM32 macros, I'm not aware of the best way to do this. I would expect something like this would suffice:

print OFFSET char


Also, have a look in the M32LIB help file (masmlib.hlp) at the IPtoString function. It is possible to use this function and only a single loop (yep, no nested loops required :wink ) to do what you are attempting - but I'll leave it as an exercise :U
Title: Re: nested loops?
Post by: marla on February 19, 2006, 12:59:48 AM
i fixed the errors, but i am getting now:

POLINK: error: Unresolved external symbol '__mainCRTStartup'.

i google and see that it might have something to do with my assembler? hmm .. what the hell is the issue this is very confusing to a newjack, especiallywhen its a reference to somethng now even in my code ...




;-----------------
; ips.asm
;-----------------

.486
.model flat, stdcall
option casemap :none

include C:\MASM32\INCLUDE\windows.inc
      include C:\masm32\macros\macros.asm
include C:\MASM32\INCLUDE\masm32.inc
      include C:\MASM32\INCLUDE\user32.inc
include C:\MASM32\INCLUDE\kernel32.inc
include C:\MASM32\INCLUDE\gdi32.inc

includelib C:\MASM32\LIB\masm32.lib
includelib C:\MASM32\LIB\user32.lib
includelib C:\MASM32\LIB\kernel32.lib
includelib C:\MASM32\LIB\gdi32.lib

;-----------------

TCP_portsCount equ 0ffffh

;-----------------

SCANINT STRUCT
   a_      DWORD ?
   b_      DWORD ?
   c_      DWORD ?
   d_      DWORD ?
   e_      DWORD ?
SCANINT ENDS

;-----------------

.data
format1 BYTE '%d.%d.%d.%d',0

;-----------------

.data?
scint   SCANINT <?>
char    BYTE 32 DUP (?)

;-----------------

.code

scanner:
xor eax,eax
mov [scint.a_], 1
mov [scint.b_], eax
mov [scint.c_], eax
mov [scint.d_], eax
mov [scint.e_], eax

    @loop_a:
      @loop_b:
          @loop_c:
              @loop_d:
                  INVOKE wsprintf,OFFSET char,OFFSET format1,[scint.a_],[scint.b_],[scint.c_],[scint.d_]
                  @loop_port:
                  print OFFSET char
                  INC [scint.e_]
                    cmp [scint.e_],TCP_portsCount
                    jle @loop_port
                INC [scint.d_]
                cmp [scint.d_], 255
                jle @loop_d
            INC [scint.c_]
            cmp [scint.c_], 255
            jle @loop_c
        INC [scint.b_]
        cmp [scint.b_], 255
        jle @loop_d
    INC [scint.a_]
    cmp [scint.a_], 254
    jle @loop_a

    invoke ExitProcess, NULL

end
;-----------------
;
;
;
;


Title: Re: nested loops?
Post by: zooba on February 19, 2006, 01:59:30 AM
The problem is you haven't told the linker where the start of your program is. Change the last line to this:

END scanner
Title: Re: nested loops?
Post by: hutch-- on February 19, 2006, 10:10:50 AM
Posted in the winasm forum under the name Marla.

Quote
how can i translate win32 masm code into opcodes/ ie: shell code?

Thread closed.