Jump to content
Tuts 4 You

Fastest way to clear all REGs


SunBeam

Recommended Posts

Hi guys. It's me again, with another kinky weird request from y'allz.

Do you happen to know the fastest way to clear all registers? (e-a-c-d-b-x, e-s-d-i)

I wrote something like this, keeping in mind I want code to be small:

_WIPE proc

push 6h

pop ecx

@loop:

push 0

loop @loop

pop eax

pop ecx

pop edx

pop ebx

pop esi

pop edi

ret

_WIPE endp

Pretty much looks like a Delphi function in prolog, lol. Post your thoughts, please!

Link to comment

What about that one (makes assumptions concerning the stack, you should mind zeroing it manually via rep movsd)?

sub esp, 0x20
mov dword ptr [esp - 0x0c], esp
sub dword ptr [esp - 0x0c], 0x20
popad

edit: Didn't save ebp though you intended to keep it as well, try that one:

mov dword ptr [esp - 0x18], ebp
mov dword ptr [esp - 0x14], esp
sub esp, 0x20
popad
Edited by metr0
Link to comment

Actually, I will modify my function with this :-)

_WIPE proc

push 6h

pop ecx

@loop:

push 0

loop @loop

popad // :-)))

ret

_WIPE endp

EDIT: Didn't know ESP and EBP are also pushed to stack on a PUSHAD o_O

Edited by SunBeam
Link to comment

Keep in mind you're pushing six zero dwords, though popping eight values from the stack. Plus, you zero ebp and esp, not sure if you want to save them?

Link to comment

Yeah, I did PUSH 8. And It wiped all but ESP on a POPAD.. Thing is I want to keep ESP and EBP from being emptied..

Edited by SunBeam
Link to comment
GamingMasteR

Hi,

You want fastest or smallest method ?

Because loops are never fast ...

XOR -> 1 Clock

PUSH+POP -> 1+1 = 2 Clocks

XOR wins

Link to comment

Smallest I meant, my bad :-) The smallest code possible.. Or, how to say this, the most COMPACT method that can be written in a few lines (2-3 lines if possible)..

P.S.: Wish there was a CASE option for registers, LOL. Like:

--

push 4h

pop ecx

@loop_1:

push 0

loop @loop_1

@loop_2:

case (a..d) X:

pop eXx

loop @loop_2

Looks like crap, but wish there was something like that :-) Or..

eAx -> inc "A" == B -> eBx -> inc "B" == C -> eCx ..

Edited by SunBeam
Link to comment
Peter Ferrie

:-) If, for some reason, the FPU were in use, then you can do it in a really obvious way:

push 0

pop eax

push eax

push eax

push eax

push eax

push eax

push ebp

push eax

push eax

popad

but it's 12 bytes and lots of lines. FPU will be empty on process start because the context is set that way.

Link to comment

I had to hit the exception from the rule, Peter. Here's the source code:

.586p
.mmx
.model flat, stdcall
option casemap :noneinclude \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
include \masm32\include\comctl32.inc
include \masm32\macros\macros.asmincludelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comctl32.lib
includelib \masm32\lib\masm32.lib.databText db "Result: ",0.data?bSpot dd ?.codeRegWipe proc push ebp
pushad
fnsave [esp-4ch]
popad
pop ebp retRegWipe endpDisplay proc fn lstrcpy, addr bSpot, hex$(ebx) fn lstrcat, addr bText, addr bSpot fn MessageBox, 0, addr bText, "Boing!", MB_OK OR MB_ICONINFORMATION fn RtlZeroMemory, addr bText+0Ah, 10h retDisplay endpFuncA proc mov AX,171
sub AX,154
mov CX,AX
shl AX,2
sub AX,CX
mov BL,AL call Display
call RegWipe retFuncA endpFuncB proc mov BX,101
mov CL,42h
sub BX,13h
shr CX,1
sub BL,CL call Display
call RegWipe retFuncB endpFuncC proc mov AX,13h
mov BX,3
mul BL
mov BL,AL call Display
call RegWipe retFuncC endpFuncD proc mov CX,7
mov AX,0C8h
idiv CL
add AL,01Bh
mov BL,AL call Display
call RegWipe retFuncD endpFuncE proc mov CX,12h
sub CX,0Ah
shl CX,1
mov BX,CX
shl CX,2
add CX,BX
sub CL,5
mov BL,CL call Display
call RegWipe retFuncE endpmain proc fn InitCommonControls call RegWipe call FuncA
call FuncB
call FuncC
call FuncD
call FuncE @end:
retmain endpend main

Main RegWipe caller:

34hjlm9.png

FPU state before calling RegWipe inside FuncA:

ofnjn9.png

And afterwards :-(

xfxqw6.png

Kinda owned me :-)

Link to comment

You don't seem to load any wicked DLL.. anyway wanted to mention it.

I once tried using FPU and MMX at the same time lol, so I remember them using the same REGs.

Just import any DLL which uses for instance mmx stuff in its init code or whatever..

and there you go.. f* up FPU REGs ^^

Link to comment
Peter Ferrie

It might also be Olly parsing something and changing the context.

You can add a fninit before the wipe. It adds only two bytes, and guarantees that the context is clean, at least at that moment.

There's also the possibility that single-stepping will give you a different result from just running directly (I know of an FPU-related single-step vs run anti-debugging trick, but this isn't it).

Also inside vs outside of a debugger. Could be a nice anti-debugging trick, if that is the case. ;-)

Link to comment

You could do this, which is a slight modification to just XORing all the registers.

XOR ECX,ECX

MUL ECX

XOR EBX,EBX

XOR ESI,ESI

XOR EDI,EDI

It's only 10 bytes and eveything else is preserved.

Sub Xero

Link to comment

^ Good one ;-) And the FINIT thingie didn't do the trick. Plus it happens both in Olly and outside of it, so it's not a debugger-only behavior.

P.S.: Had a little typo in the source above:

fn RtlZeroMemory, addr bText+08h, 8h // fixed

Edited by SunBeam
Link to comment
  • 3 weeks later...

I prefer ClearRegs!

	ClearRegs MACRO		.data
zer dd 0,0,0,0,0,0,0,0, zer
.code
xchg esp, [zer+8*4]
popad
pop esp ENDM ClearRegs1 MACRO push 32
pop ecx
sub esp, ecx
mov edi, esp
xor eax, eax
rep stosb
popad ENDM
Link to comment

To be honest, unless you have this in a loop (read: bruteforce) you wont notice the difference. If this was used in something which was time critical and was being executed millions of times, then you'd worry about clock cycles, latency and how well you can fit instructions in the pipeline to take advantage of OOE (out of order execution).

If you have a small loop that is executed many times, where the code is small enough to fit into the L1 cache, then you'll notice a difference, but otherwise most options to clear your registers will execute in a nanosecond anyway.

The MASM32 forum is a good place for information about instruction speeds, etc.

HR,

Ghandi

Link to comment
  • 3 weeks later...

@ghandi: This isn't about speed, but about SHORTER ways to do it (smaller code)

@ksbunker: Didn't know of one such macro. It's written by yourself?

@av999: Will try that one out. Feedback soon enough..

EDIT1: av999, any way to preserve EBP as well?

EDIT2: Did something like this..

.data

szPtr dd szStuff

.data?

szStuff dd 20h dup(0)

RegWipe PROC

xchg dword ptr ds:[szPtr],esp

popad

xchg dword ptr ds:[szPtr],esp

mov ebp,esp

add ebp,4

ret

RegWipe ENDP

Edited by SunBeam
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...