flat assembler
Message board for the users of flat assembler.

Index > Windows > String functions

Goto page Previous  1, 2, 3, 4  Next
Author
Thread Post new topic Reply to topic
Picnic



Joined: 05 May 2007
Posts: 1404
Location: Piraeus, Greece
Picnic 06 Feb 2013, 10:55
Yes of course, this is because fasm is not recognize this directive.
My example was quite lame, sorry about that, i'm in the office. Here is a tiny better -untested- example using dynamic memory. Hope it helps.

Code:
 dest dd ?      

Code:
        invoke HeapAlloc, <invoke GetProcessHeap>, HEAP_ZERO_MEMORY, 256
        mov [dest], eax

        stdcall szRep, source, [dest], search, replace
        invoke MessageBox, 0, [dest], "", 0

        invoke HeapFree, <invoke GetProcessHeap>, 0, [dest]
        ret
    

You're welcome!
Post 06 Feb 2013, 10:55
View user's profile Send private message Visit poster's website Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 06 Feb 2013, 12:59
HaHaAnonymous wrote:
I never used libC or use libC (not that I know, if I do, please, let me know).

It doesn't matter if you're using an actual libc - as long as you're using "strlen" or "strcpy" (etc), you're using the libc interface.

HaHaAnonymous wrote:
No, I don't care. Why? --> Because it is impossible to create something that is "un-hackable".

In other words, a waste of time.

By that line of reasoning, you should post your bank account, all personal information, all accounts and passwords.

Dunno if it's impossible to write something unhackable, but it certainly is damn hard to do any formal proofs of code correctness once there's any external input. Still, it doesn't mean we shouldn't try to write decent code, and it certainly doesn't mean we should use routines that have known security issues. Especially not when we can get safer and faster by choosing something else.

sleepsleep wrote:
vid got a complete string function implementation,
http://fasmlib.x86asm.net/

With a sane & safe interface - still (slow Razz) zero-terminated strings, though.

(No, I didn't say "vid's code is slow", I'm saying "dealing with zero-terminated strings is slower than length-prefixed strings").
Post 06 Feb 2013, 12:59
View user's profile Send private message Visit poster's website Reply with quote
JohnFound



Joined: 16 Jun 2003
Posts: 3499
Location: Bulgaria
JohnFound 06 Feb 2013, 13:15
BTW, FreshLib uses some intermediate format for dynamic strings - the string has fields .len on offset -4, but still ends with NULL, in order to be compatible with OS system API in order to not need conversion from and to asciiz. The full definition of the string structure is:
Code:
struc string {
  .capacity dd ?
  .len      dd ?
  label .data byte
}

virtual at -(sizeof.string)
  string string
  sizeof.string = $-string
end virtual    


The StrPtr procedure returns pointer to .data field of this structure, so the .capacity and .len are negative. You always can do:
Code:
stdcall StrDup, 'Test string'
stdcall StrPtr, eax
mov ecx, [esi+string.len]    
in order to get the length of the string.
Post 06 Feb 2013, 13:15
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20454
Location: In your JS exploiting you and your system
revolution 06 Feb 2013, 13:21
I've always liked this slightly better for its nicer looking column alignment:
Code:
struc string {
  .capacity dd ?
  .len      dd ?
  .data     rb 0
}    
Smile
Post 06 Feb 2013, 13:21
View user's profile Send private message Visit poster's website Reply with quote
JohnFound



Joined: 16 Jun 2003
Posts: 3499
Location: Bulgaria
JohnFound 06 Feb 2013, 13:30
Yea, it looks better. Although, recently I invented another way to make structures on negative offsets, using "struct" (here is with your trick):
Code:
struct string
  org $-sizeof.string

  .capacity dd  ?
  .len      dd  ?
  .data     rb  0
ends    
Post 06 Feb 2013, 13:30
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
Kazyaka



Joined: 10 Oct 2011
Posts: 62
Location: Earth
Kazyaka 06 Feb 2013, 13:38
Picnic,

This isn't good replacement function. I think you've noticed it too. Why? Because we need to allocate a block of memory, before we know a replaced string length. Of course, we can try provide it, but it's easy way to make program crash.

So I'm writing my custom function. If you've free time - please check what's wrong.
Code:
StringRep:
mov ebp,esp
mov edi,[ebp+4];pSourceString
mov esi,[ebp+8];pSearchString
xor ecx,ecx ;Equal bytes counter
.loop: ;Main loop
cmp byte[edi],0
je .loop_end    ;If pSourceString end then breaks the loop
mov al,[esi+ecx] ;Loads byte pSearchString + counter
cmp al,[edi] ;Compares above byte with pSearchString character
jne .not_equal
.equal: ; Both bytes are equal
add ecx,1
add edi,1
mov al,[esi+ecx]
cmp al,0
je .loop_end
jmp .loop
.not_equal: ;Both bytes aren't equal
add edi,1
xor ecx,ecx
jmp .loop
.loop_end:
invoke lstrlen, esi ;Return pSearchString length
cmp eax,ecx ;If length isn't equal with counter then returns error
jne .fail
ret
.fail:
xor eax,eax
ret    

I've added comments. The function should only checks if search string is in main string. There are only two parameters:
Code:
stdcall StringRep,SourceString,SearchString    

You can use these strings:
Code:
SourceString: db "This is string manipulation function!",0
SearchString: db "func",0    
Post 06 Feb 2013, 13:38
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20454
Location: In your JS exploiting you and your system
revolution 06 Feb 2013, 13:50
JohnFound wrote:
Yea, it looks better. Although, recently I invented another way to make structures on negative offsets, using "struct" (here is with your trick):
Code:
struct string
  org $-sizeof.string

  .capacity dd  ?
  .len      dd  ?
  .data     rb  0
ends    
Oh, but org will break the addressing space into sections. And then you can get 'out of scope' errors.
Post 06 Feb 2013, 13:50
View user's profile Send private message Visit poster's website Reply with quote
JohnFound



Joined: 16 Jun 2003
Posts: 3499
Location: Bulgaria
JohnFound 06 Feb 2013, 14:46
revolution wrote:
Oh, but org will break the addressing space into sections. And then you can get 'out of scope' errors.


Hm, it seems to work good for me... Maybe I have to make some more tests. Can you provide some example?

_________________
Tox ID: 48C0321ADDB2FE5F644BB5E3D58B0D58C35E5BCBC81D7CD333633FEDF1047914A534256478D9
Post 06 Feb 2013, 14:46
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
Asm++



Joined: 04 Feb 2013
Posts: 24
Location: On a Chip!
Asm++ 06 Feb 2013, 16:00
Kazyaka,
Asm++ wrote:
Hi, I have a little question about StringCopy(pSrc, pDest, dwBytes),
Why do we need dwBytes parameter? Question
Kazyaka wrote:
You've text "Welcome to the site of flat assembler!", and you want to copy only first word to some other place. Will you copy all bytes? Of course, not. So you must use 7 in this case as the third parameter.


Well, then it's better to rename it MemoryCopy or something like that, if you want to copy a defined number of bytes. Very Happy

_________________
Binary is nice, but Assembly is better!
Post 06 Feb 2013, 16:00
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 06 Feb 2013, 16:04
Asm++ wrote:
Well, then it's better to rename it MemoryCopy or something like that, if you want to copy a defined number of bytes. Very Happy

Indeed, that routine is a memcpy.

It would be useful, however, specifying the max size of destination - heck, even the size of source - for a string-copy routine, to avoid buffer overflows. Even just reading a buffer can be a security problem Smile
Post 06 Feb 2013, 16:04
View user's profile Send private message Visit poster's website Reply with quote
HaHaAnonymous



Joined: 02 Dec 2012
Posts: 1178
Location: Unknown
HaHaAnonymous 06 Feb 2013, 16:05
[ Post removed by author. ]


Last edited by HaHaAnonymous on 28 Feb 2015, 21:41; edited 2 times in total
Post 06 Feb 2013, 16:05
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 06 Feb 2013, 16:17
HaHaAnonymous wrote:
Asm++ wrote:

Well, then it's better to rename it MemoryCopy or something like that, if you want to copy a defined number of bytes. Very Happy

No, memory copy would be different because you would have to specify the number of bytes that want to be copied.

See the implementation of StringCopy in the original post Smile

_________________
Image - carpe noctem
Post 06 Feb 2013, 16:17
View user's profile Send private message Visit poster's website Reply with quote
Asm++



Joined: 04 Feb 2013
Posts: 24
Location: On a Chip!
Asm++ 06 Feb 2013, 16:24
HaHaAnonymous wrote:
Asm++ wrote:

Well, then it's better to rename it MemoryCopy or something like that, if you want to copy a defined number of bytes. Very Happy

No, memory copy would be different because you would have to specify the number of bytes that want to be copied.

With string this is optional as you can know where a string ends and you can copy till its end is reached. To copy part of a string is another story...you would to specify the bytes count too.


Nice, so the prototypes would be like:
MemoryCopy ( pDes, pSrc, dwBytes)
StringCopy ( pDes, pSrc )

Q-Why StringCopy must NOT to have a dwBytes parameter?
A-Because it's a STRING function(procedure, routine...), in other words its size is defined by 0(NULL), as it's a Zero Terminated String, so actually StringCopy is just a combination of StringLength(strlen) and MemoryCopy(memcpy). Smile

So, if you want to copy a part of a string, then use memcpy, and if you want to copy the whole string, then just use strcpy. Very Happy

_________________
Binary is nice, but Assembly is better!
Post 06 Feb 2013, 16:24
View user's profile Send private message Reply with quote
HaHaAnonymous



Joined: 02 Dec 2012
Posts: 1178
Location: Unknown
HaHaAnonymous 06 Feb 2013, 16:26
[ Post removed by author. ]


Last edited by HaHaAnonymous on 28 Feb 2015, 21:41; edited 1 time in total
Post 06 Feb 2013, 16:26
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 06 Feb 2013, 16:27
Asm++: even if you're going to use unsafe interfaces, please don't implement a string copy as string length + memory copy... scan over the source string twice? UGH!
Post 06 Feb 2013, 16:27
View user's profile Send private message Visit poster's website Reply with quote
Kazyaka



Joined: 10 Oct 2011
Posts: 62
Location: Earth
Kazyaka 06 Feb 2013, 16:28
Asm++,

Yeah, you're kind of right about this. But if StringCopy is MemoryCopy (saved as RtlMoveMemory in ntdll.dll), you can also say, that StringLen is like a lstrlen or strlen from WinAPI. And it'll the true. So why should you use one of my functions? Just run Cheat Engine or similar tool, and research Microsoft's procedures. They're much larger and slower. It's everything what I can say about this.
Post 06 Feb 2013, 16:28
View user's profile Send private message Reply with quote
Asm++



Joined: 04 Feb 2013
Posts: 24
Location: On a Chip!
Asm++ 06 Feb 2013, 16:39
f0dder wrote:
Asm++ wrote:
Well, then it's better to rename it MemoryCopy or something like that, if you want to copy a defined number of bytes. Very Happy

Indeed, that routine is a memcpy.

It would be useful, however, specifying the max size of destination - heck, even the size of source - for a string-copy routine, to avoid buffer overflows. Even just reading a buffer can be a security problem Smile


Yes, you are right about the buffer overflow and memory read and write violations, but the problem is how to define Save boundaries of the memory where you can manipulate it safely in all cases?
setting boundaries MANUALLY by the programmer is NOT an insurance of memory security problems, for example, setting incorrect values and... BOMB, Access Violation, Crash happy software. Shocked

_________________
Binary is nice, but Assembly is better!
Post 06 Feb 2013, 16:39
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 06 Feb 2013, 16:57
Asm++: at compile/assemble time, you know how large your static buffers are - so those can be used directly with sizeof/lengthof (please, no magic numbers scattered all over the source Razz). For dynamically allocated strings, you should be storing the length of the allocation somewhere.

Your string routines should have buffer-length arguments for both source and target strings, and you should always prefer string-base-address + index-position over pointers pointing to arbitrary positions inside your strings. At least if you want to guard against bugs (and exploits).

For nul-terminated strings, these additional checks will in some cases slow down the routines - but outside really sensitive code, IMHO the safety tradeoff is worth it. You also need to pass a few more arguments to your function, but IMHO that's not really a problem either.

If at all possible, IMHO one should be using length-prefixed strings (especially people who are worried about the small speed hit of securely dealing with nul-terminated strings). Your string-length becomes a constant-time operation, a string copy is a couple of sanity checks plus a memcopy, et cetera.
Post 06 Feb 2013, 16:57
View user's profile Send private message Visit poster's website Reply with quote
Asm++



Joined: 04 Feb 2013
Posts: 24
Location: On a Chip!
Asm++ 06 Feb 2013, 16:57
f0dder wrote:
Asm++: even if you're going to use unsafe interfaces, please don't implement a string copy as string length + memory copy... scan over the source string twice? UGH!


I think it's the "Best Solution"(NOT SURE 100%).

If I want my code to be small as possible, then I will use movsX(X = b, w, d or q), this instruction
NEEDs a COUNTER value in ECX, How to get that value if you will not find the string length first?

If I want my code to be as fast as possible, then I will NOT use movsX, but, Is it better to check for 0(NULL), Every time I read a byte value, then decide to copy it or not? Is this an efficient solution? For NOW I Don't think so(I Need to do some speed tests first to be sure). Wink

_________________
Binary is nice, but Assembly is better!
Post 06 Feb 2013, 16:57
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 06 Feb 2013, 18:24
Well, it depends on your goal - size vs. speed.

But, assuming we follow the windows/x86 register preservation rules and C calling convention, can we do a strcpy-that-relies-on-calling-strlen shorter than this?
Code:
strcpy:; 24 bytes
        push    esi
        push    edi

        mov     edi, [esp + 12] ; dst
        mov     esi, [esp + 16] ; src
        
        push    esi
        call    strlen
        mov     ecx, eax
        rep     movsb
        
        pop     eax ; to get rid of arg for strlen
        pop     edi
        pop     esi
        ret    


Here's a couple of straightforward alternatives that don't rely on first calling strlen:
Code:
strcpy_1:       ; 19 bytes
        push    esi
        push    edi
        mov     edi, [esp + 12] ; dst
        mov     esi, [esp + 18] ; src
.copy:
        lodsb
        stosb
        test    al, al
        jnz     .copy

        pop     edi
        pop     esi
        ret

strcpy_2:       ; 19 bytes
        mov     edx, [esp + 4]  ; dst
        mov     ecx, [esp + 8]  ; src
.copy:
        mov     al, [ecx]
        mov     [edx], al
        inc     ecx
        inc     edx
        test    al, al
        jnz     .copy
        ret    


Not claiming any of those are optimal (or even good, and they haven't been tested - they're just food for thought.
Post 06 Feb 2013, 18:24
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2, 3, 4  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.