I was wondering how i would be able to reverse a handcoded string to make it a null-terminate one.

For example, how would i reverse the following string and display it in a messagebox?

hello_backwards BYTE 'olleH'

I was thinking of somehow pushing+popping each char, but that seemed a bloat, and i couldn't get it to work anyways :( , but if it's a null-terminated string, won't i have to declare the backwards string as something like:

hello_backwards BYTE 0,'olleH'

?

Anybody have any ideas?

You help will be greatly appreciated


Thanks!
Posted on 2003-05-29 00:22:18 by Drocon
mov esi, OFFSET Forward
mov edi, OFFSET Backward

xor eax, eax
@@:
push eax
lodsb
test al, al
jne @B

@@:
pop eax
stosb
test eax, eax
jne @B
Posted on 2003-05-29 00:27:09 by bitRAKE
[size=12]ReverseString proc lpsrc:DWORD, lpdest:DWORD


mov esi, lpsrc
mov edi, lpdest
xor ecx, ecx

@@: cmp byte ptr [esi+ecx], 0
lea ecx, [ecx + 1]
jne @B
mov byte ptr [edi+ecx-1], 0

@@: sub ecx, 2
jl @F
mov ah, byte ptr [esi]
mov al, byte ptr [esi+ecx]
mov byte ptr [edi], al
mov byte ptr [edi+ecx], ah
inc esi
inc edi
jmp @B

@@: ret

ReverseString endp[/size]


Doesn't use the stack.
The source string and the dest buffer can overlap.
Tested and works, but not optimised.
Posted on 2003-05-29 02:38:05 by iblis
Drocon,

Also,you can use the revstr function from the masm32 library.
Posted on 2003-05-29 08:37:56 by Vortex
If you want to reverse a string, placing it over the top of the original.

If the string is short though, it'll be quicker to use a simple version, that only takes 1 byte at a time. The cost of moving 4 bytes at a time is a set-up cost which will make it less efficient for short strings.



revstr2 proc lpszSource:DWORD
invoke StrLen,lpszSource

push esi
push edi

mov edi, eax
mov esi, lpszSource
add edi, esi

and eax, 6
cmp eax, 2
jne @F

dec edi
mov al, [edi]
mov ah, [esi]
mov [esi], al
mov [edi], ah
inc esi

@@:
sub edi, 4
.WHILE esi <= edi
mov ecx, [edi]
mov edx, [esi]
bswap ecx
bswap edx
mov [esi], ecx
mov [edi], edx
add esi, 4
sub edi, 4
.ENDW

pop edi
pop esi
ret
revstr2 endp


Mirno
Posted on 2003-05-29 12:40:09 by Mirno
Here is my take on the problem... Im using xchg instead of bswap (dont know which is better really).

Rev   PROC USES ESI EDI lpString:DWORD, cLen:DWORD


mov esi, lpString
mov edi, esi
mov ecx, cLen
add edi, ecx
.if( SDWORD PTR ecx > 3 )

sub edi, 4

mov eax, [edi]
mov edx, [esi]

xchg ah, al
xchg dh, dl

rol eax, 16
rol edx, 16

xchg ah, al
xchg dh, dl

mov [edi], edx
mov [esi], eax

sub ecx, 8
add esi, 4

invoke Rev, esi, ecx

.elseif ecx == 3

mov eax, [esi]
xchg ah, al
rol eax, 16
xchg ah, al
ror eax, 8
mov [esi], eax

.elseif ecx == 2

mov eax, [esi]
xchg ah, al
mov [esi], eax

.endif

ret
Rev endp


With the following test routine:
.586

.model flat,stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\masm32.inc
include \masm32\include\debug.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\debug.lib

DBGWIN_EXT_INFO = 0
Rev PROTO lpString:DWORD, cLen:DWORD

.data
string db "0123456789ABCDEF",0

.data?

.code
start:
push ebx
mov ebx, 16
.while (ebx > 0)
PrintText " ------------------------------------[ Rev ] "
PrintString string
invoke Rev, addr string, ebx
PrintString string

dec ebx
lea edx, string
add edx, ebx
xor eax, eax
mov [edx], al
.endw
pop ebx
invoke ExitProcess, 0


end start
end

The output is (formatted to show its operations):
 ------------------------------------[ Rev ] 

string = 0123 4567 89AB CDEF
string = FEDC BA98 7654 3210
------------------------------------[ Rev ]
string = FEDC BA98765 4321
string = 1234 56789AB CDEF
------------------------------------[ Rev ]
string = 1234 56789A BCDE
string = EDCB A98765 4321
------------------------------------[ Rev ]
string = EDCB A9876 5432
string = 2345 6789A BCDE
------------------------------------[ Rev ]
string = 2345 6789 ABCD
string = DCBA 9876 5432
------------------------------------[ Rev ]
string = DCBA 987 6543
string = 3456 789 ABCD
------------------------------------[ Rev ]
string = 3456 78 9ABC
string = CBA9 87 6543
------------------------------------[ Rev ]
string = CBA9 8 7654
string = 4567 8 9ABC
------------------------------------[ Rev ]
string = 4567 89AB
string = BA98 7654
------------------------------------[ Rev ]
string = BA98765
string = 56789AB
------------------------------------[ Rev ]
string = 56789A
string = A98765
------------------------------------[ Rev ]
string = A9876
string = 6789A
------------------------------------[ Rev ]
string = 6789
string = 9876
------------------------------------[ Rev ]
string = 987
string = 789
------------------------------------[ Rev ]
string = 78
string = 87
------------------------------------[ Rev ]
string = 8
string = 8


The routine is simular to Mirno's except i chose to take the recursive route... Dont think it will make first place, but it was fun to put to gether none the less ;)

It recurses by (# of chars/8 (+1 if a remainder)) layers deep if 8 or more chars are in the string.

:alright:
:NaN:
Posted on 2003-05-29 19:07:37 by NaN
Thanks for all the wonderful help! :)
Posted on 2003-05-29 22:37:56 by Drocon

mov esi, OFFSET Forward
mov edi, OFFSET Backward

xor eax, eax
@@:
push eax
lodsb
test al, al
jne @B

@@:
pop eax
stosb
test eax, eax
jne @B


bitRake can u explain this piece of code to me ?? line after line.
Posted on 2003-05-30 04:18:55 by AceEmbler


mov esi, OFFSET Forward
mov edi, OFFSET Backward

xor eax, eax;eax=0
@@:
push eax;store value of eax on the stack
lodsb;mov al,[esi] inc esi
test al, al;test for null terminator
jne @B;continue loop if null terminator is not present

@@:
pop eax;get the value of eax from the stack
stosb;mov [edi], al inc edi
test eax, eax;test for the beginning of the string
jne @B ;if not the start of the string, continue.

I tried my best explaining.
Posted on 2003-05-30 06:04:13 by roticv

bitRake can u explain this piece of code to me ?? line after line.
roticv, has done well. Only thing I will add is that a zero dword is put on the stack so the second part knows when to stop. Look at the code run in OllyDbg and it will be very clear. I code it for size - not speed.
Posted on 2003-05-30 08:32:26 by bitRAKE
Yeah, I noticed that. That's why there is the test eax,eax which is to test for the beginning of the string (eax=0 is pushed onto the stack).

Arkane had also an algo whcih requires you to know the string length


.386
.MODEL flat, stdcall
option casemap:none

INCLUDE \masm32\include\windows.inc
INCLUDE \masm32\include\kernel32.inc
INCLUDELIB \masm32\lib\kernel32.lib
INCLUDE \masm32\include\user32.inc
INCLUDELIB \masm32\lib\user32.lib

.data

mystringdata db "hello cruel world", 0
buffer db 20 DUP(0)

.code

Start:

invoke lstrlen, OFFSET mystringdata
mov ecx, eax
mov esi, OFFSET mystringdata
mov edi, OFFSET buffer

@@:
dec ecx
mov dl, BYTE ptr [esi+ecx]
mov BYTE ptr[edi], dl
inc edi
or ecx, ecx
ja @b

invoke MessageBox, 0, OFFSET buffer, 0, 0
invoke ExitProcess, 0

END Start


Of course he could have saved 2 bytes by using eax as loop counter instead of ecx.
Posted on 2003-05-30 10:05:49 by roticv
so what will happened when stack will overload ?? for example we got very long string.
Posted on 2003-05-30 13:24:17 by AceEmbler
well, i guess the stack is pretty much defined to handle quite big amount of data,
for old 16bit i use 100h array..which pretty much too much :)
Posted on 2003-05-30 14:22:28 by wizzra
A quick test on my Windows 98SE, shows just under 1 Mb (approx 1Mb - 8K).
Here is my basic test code:
.code

start:
mov eax, esp
PrintHex eax, "Start ESP"
@@:
push eax
jmp @B

invoke ExitProcess, 0
end start


I got a starting ESP = 0064FE3Ch and a stack overflow at ESP = 00552000h
So i wouldnt be all to concerned ;)

:alright:
NaN
Posted on 2003-05-30 21:45:27 by NaN
If I am not wrong the default stack size is 1MB. However you an increase the stack size by one of the linker or ml switches.
Posted on 2003-05-30 22:25:07 by roticv
what heappens with data that i pushed on a stack and then close aplication that done it without poping it ??
Posted on 2003-05-31 17:59:59 by AceEmbler
Nothing
Posted on 2003-05-31 21:43:07 by lingo12
All process memory and resources are freed when you exit the process. The stack that you use is local to your process so it is freed as well. In effect when your process terminates it's stack and all it's contents and pointer no longer exists.
Posted on 2003-05-31 21:45:07 by donkey
It would just screw your debugger if I am not mistaken. :)
Posted on 2003-05-31 23:09:37 by roticv

All process memory and resources are freed when you exit the process. The stack that you use is local to your process so it is freed as well. In effect when your process terminates it's stack and all it's contents and pointer no longer exists.



So what for we are destroying brushes, objects and so on, when all resources are freed ??
Posted on 2003-06-01 04:01:04 by AceEmbler