News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Stack and variables

Started by acake, November 25, 2019, 12:21:38 AM

Previous topic - Next topic

acake

Basically I don't understand one thing concerning the "ebp" and "esp" registers.
I know that it is a basic question but I'm not really familiar with those two registers.

Once, I saw something like:

push 00h
push 63h
pushw 6578h
push 456e6957h
mov [ebp-4], esp


It basically push the string "WinExec\0" into the stack at "[ebp-4]", ok.
But why when I just write "[ebp-2]" or "[ebp]" it works fine, why exactly "-4" ?

esp is poiting to the top element in the stack, so why does it move all the string (that I pushed in 4 separated pieces) in "[ebp-4]"?
I'm really confused with those two registers.

Thanks for reading :).
La mort prouve l'immortalité car l'homme ne peut pas plus cesser d'être que le néant ne peut cesser de ne pas être.

hutch--

Well, first you must understand stack memory, in 32 bit PE executables, it is memory allocated for a range of purposes. This memory address is located by the stack pointer "esp". At its simplest arguments for a function call are pushed onto the stack in a specific order then a function is called by its address so you routinely get code like,

push arg3
push arg2
push arg1
call procedure

With the most commonly used calling convention in win32, STDCALL, the procedure being called must balance the stack on exit. With the example above it would terminate with a "ret 12".

This works OK on very simple procedures but when you need to have LOCAL variables in the procedure that is being called, you need to use an additional register and in this case the calling convention required EBP (the base pointer) which is used to store the locations of the local variables as memory operands.

The entry and exit from a procedure that uses LOCAL variables is a bit more complicated than the simple version but its not all that hard to perform. MASM does this when you make a normal prototyped procedure that has LOCAL variables.

What I would recommend is you get a dis-assembler and then write a simple procedure that has multiple arguments passed to it and that has LOCAL variables within it. You don't have to do much in the procedure, just use a NOP or a "mov eax, eax" then disassemble the procedure in a simple test executable and you will see exactly what MASM does with a procedure. Characteristically MASM does the exit with a LEAVE instruction which is a bit different from many compilers but it works fine.

hutch--

This is what a simple example looks like.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    testproc PROTO :DWORD,:DWORD,:DWORD

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    invoke testproc,1,2,3

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

testproc proc arg1:DWORD,arg2:DWORD,arg3:DWORD

    LOCAL var1  :DWORD
    LOCAL var2  :DWORD
    LOCAL var3  :DWORD

    mov eax, var1
    mov ecx, var2
    mov edx, var3

    ret

testproc endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start

comment #

00401010                    start:
00401010 E807000000             call    fn_0040101C
00401015 6A00                   push    0
00401017 E8E4FFFFFF             call    jmp_ExitProcess

0040101C                    fn_0040101C:
0040101C 6A03                   push    3
0040101E 6A02                   push    2
00401020 6A01                   push    1
00401022 E801000000             call    fn_00401028
00401027 C3                     ret

00401028                    fn_00401028:
00401028 55                     push    ebp
00401029 8BEC                   mov     ebp,esp
0040102B 83C4F4                 add     esp,0FFFFFFF4h
0040102E 8B45FC                 mov     eax,[ebp-4]
00401031 8B4DF8                 mov     ecx,[ebp-8]
00401034 8B55F4                 mov     edx,[ebp-0Ch]
00401037 C9                     leave
00401038 C20C00                 ret     0Ch

#

jj2007

Quote from: acake on November 25, 2019, 12:21:38 AMIt basically push the string "WinExec\0" into the stack at "[ebp-4]", ok.

Read this very important text.

acake

Quote from: jj2007 on November 25, 2019, 01:48:25 AM
Quote from: acake on November 25, 2019, 12:21:38 AMIt basically push the string "WinExec\0" into the stack at "[ebp-4]", ok.

Read this very important text.
It was really interesting and entertaining to read a second time the rules of the forum :), now I might want to ask you why ?
You would have maybe prefer something like "Bob\0", but that's not  really cool for the persons named "WinExec\0".
La mort prouve l'immortalité car l'homme ne peut pas plus cesser d'être que le néant ne peut cesser de ne pas être.

acake

#5
Thanks a lot for your answer :), it helped to find what was the exact thing I wasn't understanding, and it was the EBP register.
(That website helped me too in case someone have the same problem [Deleted]
Thanks.

Do not post malware sites in this forum.
La mort prouve l'immortalité car l'homme ne peut pas plus cesser d'être que le néant ne peut cesser de ne pas être.

jj2007

Quote from: acake on November 25, 2019, 07:38:40 AMIt was really interesting and entertaining to read a second time the rules of the forum :), now I might want to ask you why ?
You would have maybe prefer something like "Bob\0", but that's not  really cool for the persons named "WinExec\0".

In our experience, typically script kiddies trying their luck with assembly would try to use good ol' WinExec to launch a payload. It is up to you to explain your intentions. Don't be shy, but try to give a convincing explanation.

acake

"Script Kiddie".
That's why I don't like talking to the pseudo-experienced people when I'm trying to learn again some random stuff.
I can understand the fact that arrogance is inherent in humans but no material entity would answer to your question if you talk to it like that.
I'll let you reformulate your question if you want any serious answer.

But yeah I can understand that you might have thought of a shellcode (on basic shellcodes, non-obfuscated one, we can find that kind of instructions, true, but that isn't really elegant if you want my point of view).

I'm not here to ask tips to code any form of malicious program/code, I was just wondering how those manipulations of the ebp register were working in a theoretical way.

The clearnet might be a form of big joke I can't get.

Thanks.
La mort prouve l'immortalité car l'homme ne peut pas plus cesser d'être que le néant ne peut cesser de ne pas être.

jj2007

Instead of explaining what are your intentions, you are insulting me. That tells us something :thumbsup:

acake

Can I know where I insulted you ?
I also told you why I didn't wanted to explain you anything.
La mort prouve l'immortalité car l'homme ne peut pas plus cesser d'être que le néant ne peut cesser de ne pas être.

cman

Quotebut that's not  really cool for the persons named "WinExec\0".
Interesting name.  :biggrin:

aw27

Shell code does not work by pushing on the stack a string with an API function name.
The address of the function is what needs to be pushed to be shell code and this becoming more and more difficult with ALR.
Your question was a good one and you received a proper answer from Hutch.
I hope you have not been scared by the site's troll and hope to see you around more times.

acake

Quote from: AW on November 26, 2019, 06:51:53 AM
Shell code does not work by pushing on the stack a string with an API function name.
The address of the function is what needs to be pushed to be shell code and this becoming more and more difficult with ALR.
Your question was a good one and you received a proper answer from Hutch.
I hope you have not been scared by the site's troll and hope to see you around more times.
Yes, Hutch gave me the answer I needed.
And yeah I know, but you still need the name of the function to finally find it's RVA in the AddressOfFunction array.

And thanks :), I need more to get scared hahaha.
La mort prouve l'immortalité car l'homme ne peut pas plus cesser d'être que le néant ne peut cesser de ne pas être.

hutch--

acake,

Understand why you get this response, this forum has been running for years and over time we have had many shifty little bastards try and sneak questions about how to do malicious things in code like virus technology, cooking up viruses and designing security hacks but they run into the same thing, a forum with many people who can spot this crap as soon as its posted. We use a policy here of "Shoot first and ask questions later" because we have been caught too many times in the past.

When someone asks an innocent question that can be misunderstood, if they tell us what they are doing, all is well but if we get fed bullsh*t or an evasive answer we have the option of setting them free on the internet to get support for what they are after (IE: kicked out faster than Haleys comet).

Now the other factor is that as I am responsible for what gets posted in this forum and under no circumstances will I protect anyone who posts illegal stuff and I will deliberately assist any security agency in the world to track down the perpetrator so that the secret police come to their door at 3am, smash it down, beat the sh*t out of them and cart them off to some secret prison where they will rot for eternity.  :biggrin:

I hope you have understood the relationship of the stack pointer and base pointer as it is useful technology to understand.