question in <<Analyze This - Analyzing a Crash Dump>>

Article http://www.osronline.com/article.cfm?article=38

u 8015c914
NT!_ExpCopyProcessInfo@8+0x0:
8015C914 53 push ebx
8015C915 56 push esi
8015C916 57 push edi
8015C917 8B7C2414 mov edi,dword ptr [esp+14h]
8015C91B 8B8704010000 mov eax,dword ptr [edi+104h]
8015C921 85C0 test eax,eax
8015C923 740C je _ExpCopyProcessInfo@8+1Dh
8015C925 8B4014 mov eax,dword ptr [eax+14h]

Since the previous three instructions pushed three values onto the stack and the function return address is also stored there, we note that this looks to be referencing parameter two (with parameter 1 at 0x10 from the current stack pointer). Oh, don?t forget that stacks grow down so arguments above the current stack address (at a positive offset) are values on the stack.

Q:
and the function return address is also stored there

Does function return address always stored in stack?

Q:
with parameter 1 at 0x10 from the current stack pointer

How can we determine that the function need more than 1 parameters?
And
What clues can we decide that 0x10 is parameter one?

Does this address calculated by 0x14-0x4(void pointer with 4 bytes)?

On Fri, Aug 2, 2013 at 9:37 AM, wrote:

>
> Q:
> and the function return address is also stored there
>
> Does function return address always stored in stack?
>

Yes, the return address is stored on the stack by the CALL instruction.

>
> Q:
> with parameter 1 at 0x10 from the current stack pointer
>
> How can we determine that the function need more than 1 parameters?
>

Well, generally, you can’t unless you have private symbols for the
function. However, when you see the function referencing ESP+something,
it’s likely to assume that these are the function’s parameters.

> And
> What clues can we decide that 0x10 is parameter one?
>

Here’s a little picture of the stack structure at the point of the MOV EDI,
DWORD PTR [ESP+0x14] instruction:

ESP saved edi
ESP+4 saved esi
ESP+8 saved ebx
ESP+12 return address
ESP+16 first parameter
ESP+20 second parameter

When you enter the function, ESP points to the return address. The first
parameter is then at ESP+4 and the second parameter is at ESP+8. However,
the function starts by pushing three 32-bit registers onto the stack, which
results in ESP being decremented by 12. Therefore, ESP+16 (ESP+0x10) is the
first parameter and ESP+20 (ESP+0x14) is the second parameter.

HTH,
Sasha

thank you Sasha.

ESP saved edi
ESP+4 saved esi
ESP+8 saved ebx
ESP+12 return address
ESP+16 first parameter
ESP+20 second parameter

Does the sequence of stack push related to different function call catergory?
Such as fast call different from other calls?

call instruction only pushes return address on stack

call conventions defined by compiler

so return address always on stack, everything else depends (on compiler)

On Fri, Aug 2, 2013 at 6:45 PM, wrote:

> thank you Sasha.
>
> ESP saved edi
> ESP+4 saved esi
> ESP+8 saved ebx
> ESP+12 return address
> ESP+16 first parameter
> ESP+20 second parameter
>
> Does the sequence of stack push related to different function call
> catergory?
> Such as fast call different from other calls?
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

this stuff explained really good in “assembly language for x86 processors”
by Kip Irvine

On Fri, Aug 2, 2013 at 6:55 PM, Sergey Pisarev wrote:

> call instruction only pushes return address on stack
>
> call conventions defined by compiler
>
> so return address always on stack, everything else depends (on compiler)
>
>
> On Fri, Aug 2, 2013 at 6:45 PM, wrote:
>
>> thank you Sasha.
>>
>> ESP saved edi
>> ESP+4 saved esi
>> ESP+8 saved ebx
>> ESP+12 return address
>> ESP+16 first parameter
>> ESP+20 second parameter
>>
>> Does the sequence of stack push related to different function call
>> catergory?
>> Such as fast call different from other calls?
>>
>>
>> —
>> NTDEV is sponsored by OSR
>>
>> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>>
>> OSR is HIRING!! See http://www.osr.com/careers
>>
>> For our schedule of WDF, WDM, debugging and other seminars visit:
>> http://www.osr.com/seminars
>>
>> To unsubscribe, visit the List Server section of OSR Online at
>> http://www.osronline.com/page.cfm?name=ListServer
>>
>
>

Actually MSDN has a reasonable explanation at
http://msdn.microsoft.com/en-us/library/k2b2ssfy.aspx

Don Burn
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Sergey Pisarev
Sent: Friday, August 02, 2013 11:06 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] question in <>

this stuff explained really good in “assembly language for x86 processors”
by Kip Irvine

On Fri, Aug 2, 2013 at 6:55 PM, Sergey Pisarev
wrote:

call instruction only pushes return address on stack

call conventions defined by compiler

so return address always on stack, everything else depends (on
compiler)

On Fri, Aug 2, 2013 at 6:45 PM, wrote:

thank you Sasha.

ESP saved edi
ESP+4 saved esi
ESP+8 saved ebx
ESP+12 return address
ESP+16 first parameter
ESP+20 second parameter

Does the sequence of stack push related to different
function call catergory?
Such as fast call different from other calls?


NTDEV is sponsored by OSR

Visit the list at:
http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars
visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online
at http://www.osronline.com/page.cfm?name=ListServer

— NTDEV is sponsored by OSR Visit the list at:
http://www.osronline.com/showlists.cfm?list=ntdev OSR is HIRING!! See
http://www.osr.com/careers For our schedule of WDF, WDM, debugging and other
seminars visit: http://www.osr.com/seminars To unsubscribe, visit the List
Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

The registers are pushed onto the stack because these three registers on x86 are non volatile (must be preserved across function calls). So if a function intends to modify them, it stores them in the prologue and restores them in the epilogue. 

The fastcall calling convention dictates that the first two integer parameters are passed in ECX and EDX. If that was the case in our situation, ESP+0x10 would point to the third parameter.

On Fri, Aug 2, 2013 at 5:45 PM, null wrote:

> thank you Sasha.
> ESP saved edi
> ESP+4 saved esi
> ESP+8 saved ebx
> ESP+12 return address
> ESP+16 first parameter
> ESP+20 second parameter
> Does the sequence of stack push related to different function call catergory?
> Such as fast call different from other calls?
> —
> NTDEV is sponsored by OSR
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
> OSR is HIRING!! See http://www.osr.com/careers
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
> To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

> Does function return address always stored in stack?

Yes.

All calling conventions in Windows require CALL opcode, which pushes the return address on the stack.

What clues can we decide that 0x10 is parameter one?

At function entry, the last word on the stack is return address. Then just monitor PUSH/POP opcodes.

Also: read more about calling conventions in Windows x86and


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

> Does the sequence of stack push related to different function call catergory?

Such as fast call different from other calls?

__fastcall (with @ThisNameDecorationStyle@4) uses ECX and EDX for first 2 parameters.

__thiscall (only used for C++ methods) uses ECX for “this”.

__stdcall (default for WDK, default for all Windows umode and kmode APIs, _ThisNameDecorationStyle@4) uses stack for all arguments. The callee must unload them from the stack using RET N opcode.

__cdecl (default for MSVC, default for all portable C runtime APIs like _fopen, decoration is - add an underscore) uses stack for all arguments. The caller must unload them using the sequence of:

push arg2
push arg1
call _MyFunc
add esp, 8

  • which allows variable number of arguments.

Note that, on x64, registers RCX/RDX/R8/R9 are used for the first 4 parameters. The stack space is really allocated for them too, but it is not filled in the free build - only the checked builds do copy the args from registers to the stack frame.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

Still not clear about

  1. ESP+0x10 is first or third or the last parameter?

Third: ECX and EDX for first 2 parameters.
First: this paper.

Last:
From MSDN:
The first two DWORD or smaller arguments are passed in ECX and EDX registers; all other arguments are passed right to left.

Because args passed right to left, if there are 3 paras( p1, p2, p3), should I consider ESP+0x10 is p3?

stacks grow down

Does it means the case:

ESP –> address 0x8000,0020
ESP+0x4 –> address 0x8000,001c
ESP+0x8 –> address 0x8000,0018

  1. current stack pointer
    Does ESP is the meaning of current stack
    pointer?

Sorry for my confusing, in my opinion, stack pointer is a pointer which point to the last (full or empty) element push to this stack.

So my confusing is
there are
ESP saved edi
ESP+4 saved esi
ESP+8 saved ebx
ESP+12 return address
ESP+16 first parameter
ESP+20 second parameter

so many element in the stack, why the stack pointer still at the edi element?

8015C914 53 push ebx
8015C915 56 push esi
8015C916 57 push edi
8015C917 8B7C2414 mov edi,dword ptr [esp+14h]

If we consider esp+0x14 is a parameter,
but from this code,

It seems that ebx, esi, edi enter to the stack later than parameter of function.
Does my guess right?

i don’t have your threads context this is a general reply of stack layout

  1. when a call is issued it pushes the return address on the stack

call opcodes can be of several types and their length
see example from 2 byte call to 6 byte call

0040102E E8 B7F7047E CALL user32.MessageBoxA
00401033 E8 E2FFFFFF CALL msgbox.MessageBoxA ; JMP to user32.MessageBoxA
00401038 FFD0 CALL NEAR EAX ; user32.MessageBoxA
0040103A FF15 70304000 CALL NEAR DWORD PTR DS:[403070] user32.MessageBoxA
depending on the length of opcodes return address will also vary in
example above

ESP ==> 0013FFC0 00401033 /CALL to MessageBoxA (40102e+5)
ESP ==> 0013FFBC 00401038 /CALL to MessageBoxA (401033+5)
ESP ==> 0013FFB8 0040103A /CALL to MessageBoxA (401038+2)
ESP ==> 0013FFB4 00401040 /CALL to MessageBoxA (40103A+6)

and each of the return address will always be at esp when you enter
the call via step in

parameters are pushed in reverse order (right to left)

A Simple MessageBoxA is prototyped thus

int WINAPI MessageBox(
In_opt HWND hWnd,
In_opt LPCTSTR lpText,
In_opt LPCTSTR lpCaption,
In UINT uType
);

so uType will be pushed first in the stack and hWnd Will Be pushed
last before call is issued

ESP ==> 0013FFA0 00401013 /CALL to MessageBoxA from msgbox.0040100E
ESP+4 0013FFA4 00000000 |hOwner = NULL
ESP+8 0013FFA8 00403019 |Text = “c++32 Assembly is Great!”
ESP+C 0013FFAC 00403000 |Title = “Iczelion’s tutorial no.2”
ESP+10 0013FFB0 00000000 \Style = MB_OK|MB_APPLMODAL

in this example all the parameters are 32 bits so for 4 parameters it
will be 0n16 / 0x10 bytes
so esp + 0x10 will hold the uType Parameter
esp + 0xc will hold the lpCaption esp+ 0x8 will hold the lpText and
esp+0x4 will hold the hWnd esp will hold the return address

this pattern applies for all calls that are _stdcall

i am not sure why esp+0x10 in your case would hold the third parameter
since you say first two parameters were passed via registers
if first two parameters were passed via registers then the third
parameter will be at esp+0x4
not at esp+0x10

esp+0x10 would hold the sixth parameter if it existed

esp == extended stack pointer
the top of the stack when you enter any call
by enter I mean you have reached the first instruction and have not
executed it yet

in the snippet you posted

8015C914 53 push ebx
when you are on this instruction

esp will point to the return address if this sequence was called from somewhere

when you execute push ebx
esp will hold what was in ebx and esp+4 will hold return address

when you execute push esi

esp will hold what was in esi and esp+8 will hold return address

when you execute push edi

esp will hold what was in edi and esp+0xc will hold return address

ESP ==> 0013FF94 00560000
ESP+4 0013FF98 7C9115F9 RETURN to ntdll.7C9115F9 from ntdll._SEH_epilog
ESP+8 0013FF9C 7FFDE000
ESP+C 0013FFA0 00401013 RETURN to msgbox.+13
from msgbox.MessageBoxA
ESP+10 0013FFA4 00000000
ESP+14 0013FFA8 00403019 ASCII “c++32 Assembly is Great!”
ESP+18 0013FFAC 00403000 ASCII “Iczelion’s tutorial no.2”
ESP+1C 0013FFB0 00000000

the argument have already been pushed into stack before call
so [esp+0x14] what you describe will either be the fifth param in
case of no register passing
and seventh parameter in case two parameters were passed via register

hope i didn’t make it more confusing from where you started :slight_smile:

On 8/7/13, workingmailing@163.com wrote:
> Still not clear about
>
> 1. ESP+0x10 is first or third or the last parameter?
>
> Third: ECX and EDX for first 2 parameters.
> First: this paper.
>
> Last:
> From MSDN:
> The first two DWORD or smaller arguments are passed in ECX and EDX
> registers; all other arguments are passed right to left.
>
> Because args passed right to left, if there are 3 paras( p1, p2, p3), should
> I consider ESP+0x10 is p3?
>
> 2.
> stacks grow down
>
> Does it means the case:
>
> ESP –> address 0x8000,0020
> ESP+0x4 –> address 0x8000,001c
> ESP+0x8 –> address 0x8000,0018
>
> 3. current stack pointer
> Does ESP is the meaning of current stack
> pointer?
>
> Sorry for my confusing, in my opinion, stack pointer is a pointer which
> point to the last (full or empty) element push to this stack.
>
> So my confusing is
> there are
> ESP saved edi
> ESP+4 saved esi
> ESP+8 saved ebx
> ESP+12 return address
> ESP+16 first parameter
> ESP+20 second parameter
>
> so many element in the stack, why the stack pointer still at the edi
> element?
>
>
> 4.
> 8015C914 53 push ebx
>
> 8015C915 56 push esi
>
> 8015C916 57 push edi
>
> 8015C917 8B7C2414 mov edi,dword ptr [esp+14h]
>
> If we consider esp+0x14 is a parameter,
> but from this code,
>
> It seems that ebx, esi, edi enter to the stack later than parameter of
> function.
> Does my guess right?
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

> i don’t have your threads context this is a general reply of stack layout

  1. when a call is issued it pushes the return address on the stack

call opcodes can be of several types and their length
see example from 2 byte call to 6 byte call

0040102E E8 B7F7047E CALL user32.MessageBoxA
00401033 E8 E2FFFFFF CALL msgbox.MessageBoxA ; JMP to
user32.MessageBoxA
00401038 FFD0 CALL NEAR EAX ; user32.MessageBoxA

Just note that in Win32 the words NEAR and FAR are meaningless noise words
and should never appear in any dicussion of 32-bit code.

0040103A FF15 70304000 CALL NEAR DWORD PTR DS:[403070]
user32.MessageBoxA
depending on the length of opcodes return address will also vary in
example above

I have no idea what this sentence means. The ESP will point to a 32-bit
location on the stack that is the address of the instruction that follows
the CALL. This is not a deep concept.

ESP ==> 0013FFC0 00401033 /CALL to MessageBoxA (40102e+5)
ESP ==> 0013FFBC 00401038 /CALL to MessageBoxA (401033+5)
ESP ==> 0013FFB8 0040103A /CALL to MessageBoxA (401038+2)
ESP ==> 0013FFB4 00401040 /CALL to MessageBoxA (40103A+6)

and each of the return address will always be at esp when you enter
the call via step in

parameters are pushed in reverse order (right to left)

A Simple MessageBoxA is prototyped thus

int WINAPI MessageBox(
In_opt HWND hWnd,
In_opt LPCTSTR lpText,
In_opt LPCTSTR lpCaption,
In UINT uType
);

so uType will be pushed first in the stack and hWnd Will Be pushed
last before call is issued

ESP ==> 0013FFA0 00401013 /CALL to MessageBoxA from msgbox.0040100E
ESP+4 0013FFA4 00000000 |hOwner = NULL
ESP+8 0013FFA8 00403019 |Text = “c++32 Assembly is Great!”
ESP+C 0013FFAC 00403000 |Title = “Iczelion’s tutorial no.2”
ESP+10 0013FFB0 00000000 \Style = MB_OK|MB_APPLMODAL

in this example all the parameters are 32 bits so for 4 parameters it
will be 0n16 / 0x10 bytes
so esp + 0x10 will hold the uType Parameter
esp + 0xc will hold the lpCaption esp+ 0x8 will hold the lpText and
esp+0x4 will hold the hWnd esp will hold the return address

this pattern applies for all calls that are _stdcall

i am not sure why esp+0x10 in your case would hold the third parameter
since you say first two parameters were passed via registers
if first two parameters were passed via registers then the third
parameter will be at esp+0x4
not at esp+0x10

esp+0x10 would hold the sixth parameter if it existed

esp == extended stack pointer
the top of the stack when you enter any call
by enter I mean you have reached the first instruction and have not
executed it yet

in the snippet you posted

8015C914 53 push ebx
when you are on this instruction

esp will point to the return address if this sequence was called from
somewhere

when you execute push ebx
esp will hold what was in ebx and esp+4 will hold return address

when you execute push esi

esp will hold what was in esi and esp+8 will hold return address

when you execute push edi

esp will hold what was in edi and esp+0xc will hold return address

ESP ==> 0013FF94 00560000
ESP+4 0013FF98 7C9115F9 RETURN to ntdll.7C9115F9 from
ntdll._SEH_epilog
ESP+8 0013FF9C 7FFDE000
ESP+C 0013FFA0 00401013 RETURN to msgbox.+13
> from msgbox.MessageBoxA
> ESP+10 0013FFA4 00000000
> ESP+14 0013FFA8 00403019 ASCII “c++32 Assembly is Great!”
> ESP+18 0013FFAC 00403000 ASCII “Iczelion’s tutorial no.2”
> ESP+1C 0013FFB0 00000000
>
>
> the argument have already been pushed into stack before call
> so [esp+0x14] what you describe will either be the fifth param in
> case of no register passing
> and seventh parameter in case two parameters were passed via register
>
> hope i didn’t make it more confusing from where you started :slight_smile:
>
>
>
This constant shifting of the parameter position relative to ESP is why
most functions start out with

push ebp
mov ebp, esp

Note now that while ESP may bounce around a lot, EBP remains fixed. So
[EBP] points to the “old EBP”, [EBP+4] is the return address, [EBP+8] is
the leftmost parameter, and so on. The result is a “linked list” of stack
frames that can be followed to get the “stack trace”. If Frame Pointer
Optimization is enabled, EBP is not used, and the compiler tracks ESP
intruction by instruction. The resulting code is very difficult for a
human being to follow. For exaple, suppose at ESP+10 (which will be
EBP+14) the input parameter “a” will be found. Then, if FPO is off, the
call
whatever(a, a)

will be
push [ebp+14]
push [ebp+14]
call whatever

but
if FPO is on, the code is

push [esp+140]
push [esp+144]
call whatever

so why isn’t it [esp+10] and [esp+14]? Because by the time you get here,
esp has been incremented to reserve space for the local variables. Note
also that in optimized code, a local variable may or may not have space
allocated on the stack, and a change in some unrelated part of the
function, perhaps well after this call, may result in a different
allocation of local variables, and thus the next time you see this call,
it might be
push [esp+13C]
push [esp+140]
call whatever

or
push [esp+148]
push [esp+14C]
call whatever

Code like this is a nightmare to read, which is why the use of FPO is
generally discouraged.

Historical footnote: the notion of FPO was invented by the BLISS-11
compiler group at CMU in the early 1970s. The PDP-11 had only 8
registers, R0…R7, and from our perspective, R7 == EIP and R6 == ESP, so
using up one of the scarce and valuable remaining registers for an EBP
equivalent was not considered a viable option. I spent many a late night
in a cold computer room trying to debug my OS code, learning how to
decrypt this code. So, on the whole, FPO doesn’t freak me out; it’s more
like, ho-hum, it’s 1100 instructions in, do you know where YOUR esp is?
joe
>
>
>
>
>
>
>
>
>
> On 8/7/13, workingmailing@163.com wrote:
>> Still not clear about
>>
>> 1. ESP+0x10 is first or third or the last parameter?
>>
>> Third: ECX and EDX for first 2 parameters.
>> First: this paper.
>>
>> Last:
>> From MSDN:
>> The first two DWORD or smaller arguments are passed in ECX and EDX
>> registers; all other arguments are passed right to left.
>>
>> Because args passed right to left, if there are 3 paras( p1, p2, p3),
>> should
>> I consider ESP+0x10 is p3?
>>
>> 2.
>> stacks grow down
>>
>> Does it means the case:
>>
>> ESP –> address 0x8000,0020
>> ESP+0x4 –> address 0x8000,001c
>> ESP+0x8 –> address 0x8000,0018
>>
>> 3. current stack pointer
>> Does ESP is the meaning of current stack
>> pointer?
>>
>> Sorry for my confusing, in my opinion, stack pointer is a pointer which
>> point to the last (full or empty) element push to this stack.
>>
>> So my confusing is
>> there are
>> ESP saved edi
>> ESP+4 saved esi
>> ESP+8 saved ebx
>> ESP+12 return address
>> ESP+16 first parameter
>> ESP+20 second parameter
>>
>> so many element in the stack, why the stack pointer still at the edi
>> element?
>>
>>
>> 4.
>> 8015C914 53 push ebx
>>
>> 8015C915 56 push esi
>>
>> 8015C916 57 push edi
>>
>> 8015C917 8B7C2414 mov edi,dword ptr [esp+14h]
>>
>> If we consider esp+0x14 is a parameter,
>> but from this code,
>>
>> It seems that ebx, esi, edi enter to the stack later than parameter of
>> function.
>> Does my guess right?
>>
>>
>> —
>> NTDEV is sponsored by OSR
>>
>> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>>
>> OSR is HIRING!! See http://www.osr.com/careers
>>
>> For our schedule of WDF, WDM, debugging and other seminars visit:
>> http://www.osr.com/seminars
>>
>> To unsubscribe, visit the List Server section of OSR Online at
>> http://www.osronline.com/page.cfm?name=ListServer
>>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

> Still not clear about

  1. ESP+0x10 is first or third or the last parameter?

Try writing
void __fastcall test(int x, int y, int z)
{
}

Then code
test(1, 2, 3)
Set a breakpoint and see where the values are.

It is often more productive to run an experiment than to ask a question or
read the documentation.

You can only trust the results if optimization is completely turned off.

Third: ECX and EDX for first 2 parameters.
First: this paper.

Last:
From MSDN:
The first two DWORD or smaller arguments are passed in ECX and EDX
registers; all other arguments are passed right to left.

Because args passed right to left, if there are 3 paras( p1, p2, p3),
should I consider ESP+0x10 is p3?

See previous comment. I don’t recall, but this is such a screamingly
obvious experiment I’m surprised you didn’t try it.

stacks grow down

Does it means the case:

ESP –> address 0x8000,0020
ESP+0x4 –> address 0x8000,001c
ESP+0x8 –> address 0x8000,0018

No. The stack *grows* down. It means exactly what it says when you write
ESP+4: the value 4 is added to the value in ESP to get the address. Note
that each “push” and the “call” each decrement ESP. So, before the last
parameter was pushed, the value of ESP was 0x8000014C. Note that these
offsets are correct ONLY if you set a breakpoint at the very first
instruction (NOT first-line-of-C-code) of the function.

p3 ESP+C 0x80000148
p2 ESP+8 0x80000144
p1 ESP+4 0x80000140
retaddr ESP 0x8000013C

  1. current stack pointer
    Does ESP is the meaning of current stack
    pointer?

Sorry for my confusing, in my opinion, stack pointer is a pointer which
point to the last (full or empty) element push to this stack.

ESP points to the current stack position. There is no concept of “full”
or “empty” here. Note that in general you will see, if any local
variables are used
sub ESP, nnn
where nnn represents the amount of space needed for the local variables,
“rounded” up to the nearest multiple of 4 (for Win32).

The current ESP now points to a location which is the top of the stack.
In production code, this means that all local variables you do not
initialize before their use inherit whatever garbage values that had been
left on the stack.

So my confusing is
there are
ESP saved edi
ESP+4 saved esi
ESP+8 saved ebx
ESP+12 return address
ESP+16 first parameter
ESP+20 second parameter

so many element in the stack, why the stack pointer still at the edi
element?

Because edi is the current top of the stack! There may be several
THOUSAND values below the second parameter, but “below” on a stack means
“at higher addresses”

Since you are so interested in this, write some test apps. Make sure all
optimizations are off, but “debug” mode is not selected (in app space,
this results in a lot of extra code for debugging prolog. Once you
understand what the basic behavior is, you can then do a debug build and
study what it does). Turn on the compiler option for listing, mixed
source, assembly, and code. Study the listing. The set a breakpoint at
the call to the function and, one instruction at a time, single-step, and
watch what each instruction does. You should bring up a memory display
window, and at the breakpoint set it to show the memory at esp, and a
register-display window, so you can watch the registers change.

Ok, here’s a trick question. Those of you who know the answer, keep quiet
until the OP answers.

int i = 0;
int data = { 9, 10, 11, 12};

func(i++, data[i]);
or
func(++i, data[i]);
or
func(i, data[i++]);
or
func(i, data[++i]);
or
func(data[i], i++);
or
func(data[i], ++i);
or
func(i, data[i++]);
or
func(i, data[++i]);

if the function is

void func(int a, int b)
{
// print a=%d, b=%d\n
}

Hint: the answer is not what you might expect it to be. You can probably
save a lot of time by reading the C language spec on parameters. After
you do some research and post the answer, we’ll tell you if you are
correct.

(And yes, I know this is a trick question, but when you are down looking
at the generated assembly code, understanding the implications becomes a
whole lot more important. So give the OP a chance, guys, before jumping
in)

8015C914 53 push ebx
8015C915 56 push esi
8015C916 57 push edi
8015C917 8B7C2414 mov edi,dword ptr [esp+14h]

If we consider esp+0x14 is a parameter,
but from this code,

It seems that ebx, esi, edi enter to the stack later than parameter of
function.
Does my guess right?

Yes. The sequence is
push rightmost parameter value

push leftmost paramter value
push return address and jump to function (call instruction)
function prologue
save frame pointer if necessary
set current frame pointer to stack pointer
save preservable registers this function will need to use
decrement stack pointer to make room for local variables
…body of functiom
function epilog
strip locals from stack
pop saved registers
pop frame pointer
pop return address to EIP
upon return from call
increment ESP to strip parameters from stack

Now, many of these actions are omitted if not required. For example, if
the function only uses transient registers for its computations (those
registers whose content does not need to be saved), the the register saves
are not made, and the restores are not done. If the function does not use
a frame pointer, it isn’t saved. If local variables are not needed, they
won’t be allocated or stripped. If __stdcall or __fastcall are used, the
action of popping the return address to EIP and incrementing esp to strip
the paramters is a single instruction: RET n, and therefore, there will be
no increment of the stack pointer after the call instruction.

Note that you can do all these experiments in user space to see what happens.
joe


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Thank you very much. raj.

depending on the length of opcodes return address will also vary in
example above

But I saw, the return address always be 4bytes, not only in your example, but other cases.

It is right, no matter the opcode length, the return address at 32bit os should be 4 bytes.

  1. esp+0x10 would hold the sixth parameter if it existed

If it is fast call, it should be third parameter.

Stack

esp + 0x14 : para 4(if existed)
esp + 0x10 : para 3
esp + 0x0c : return address
esp + 0x08 : ebx
esp + 0x04 : esi
esp + 0x00 : edi

>>But I saw, the return address always be 4bytes, not only in your example, but other cases.

yes on 32 bit it is always 4 bytes it is an address no other
interpretation exists

ill try to make the statement a bit more clear as the good old doctor
also took a shot at it :slight_smile:

call opcodes can be variable length

so if a call was issued at 401000 with a 5 byte opcode sequence
the return address that will be pushed into stack will be 401005

like wise if the call was issued with a 2 byte opcode sequence at 401000
the return address pushed will be 401002 and so on

hope now the statement makes a bit more sense

-----> push :slight_smile: will drop down +0x04 on 32 bits per push
=============== pop will make it come up
stack top esp+0x00 | | | 4 bytes per instruction in 32 bit
| | |
| \ / |
| ^ _^ |
| | |
stack bot esp+0xNN | / |
++++++++++

On 8/9/13, workingmailing@163.com wrote:
> Thank you very much. raj.
>
> 1.
> depending on the length of opcodes return address will also vary in
> example above
>
> But I saw, the return address always be 4bytes, not only in your example,
> but other cases.
>
> It is right, no matter the opcode length, the return address at 32bit os
> should be 4 bytes.
>
> 2. esp+0x10 would hold the sixth parameter if it existed
>
> If it is fast call, it should be third parameter.
>
> Stack
> =====================
> esp + 0x14 : para 4(if existed)
> esp + 0x10 : para 3
> esp + 0x0c : return address
> esp + 0x08 : ebx
> esp + 0x04 : esi
> esp + 0x00 : edi
> =====================
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

opps sorry for posting back to back hit enter too soon

your interpertation diagram is kinda wrong

always print / think /visialize /emphasize and dream stack position as
top to bottom
it makes concepts clear to self and to others

esp is always return address (WHEN YOU ARE ON FIRST INSTRUCTION in
ASSEMBLY MODE of a CALL (like Dr newcomer pointed out not when you
step in in c or higher level language using fancy studios)

parameter 0x1 is always esp+0x4
parameter 0x2 is always esp+0x8
parmater 0xN is always esp+ (0x4*0xN)

the ebx ecx whatever you posted will always be above return address

so if you are not first instruction but have stepped into the call 3
instructions
and if they were
push ebx
push esi
push edi

your stack will look like

esp +0x0 saved edi
esp+0x04 saved esi
esp+0x08 saved ebx
esp+0x0c return address
esp+0x10 param 1
esp+0x14 param 2

esp+0xNN param …

earlier data from parent calls or garbage
below this

and as Dr Newcomer rightly posted
write simple usermode application load it in a debugger and watch how
things appear
one visual is equivalent to ten dry books or 100 forum posts

write a simple foo.c
type WINAPI WinMain(…)
{
MessageboxA(…)
Exitprocess()
}

compile with cl /c o1 foo.c

Link with
link /ENTRY:WinMain foo.obj user32.lib kernel32.lib

since you define entrypoint all the c runtime codes will be bypassed
and disassembly will be relatively clear

load it in debugger set bp WinMain run

when you hit the breakpoint single step in from start till ExitProcess
you will learn much much much more than asking on this or any other forum

On 8/9/13, raj_r wrote:
>>>But I saw, the return address always be 4bytes, not only in your example,
>>> but other cases.
>
> yes on 32 bit it is always 4 bytes it is an address no other
> interpretation exists
>
> ill try to make the statement a bit more clear as the good old doctor
> also took a shot at it :slight_smile:
>
> call opcodes can be variable length
>
> so if a call was issued at 401000 with a 5 byte opcode sequence
> the return address that will be pushed into stack will be 401005
>
> like wise if the call was issued with a 2 byte opcode sequence at 401000
> the return address pushed will be 401002 and so on
>
> hope now the statement makes a bit more sense
>
>
> -----> push :slight_smile: will drop down +0x04 on 32 bits per
> push
> =============== pop will make it come up
> stack top esp+0x00 | | | 4 bytes per instruction in 32
> bit
> | | |
> | \ / |
> | ^ _^ |
> | | |
> stack bot esp+0xNN | / |
> ++++++++++
>
>
>
> On 8/9/13, workingmailing@163.com wrote:
>> Thank you very much. raj.
>>
>> 1.
>> depending on the length of opcodes return address will also vary in
>> example above
>>
>> But I saw, the return address always be 4bytes, not only in your example,
>> but other cases.
>>
>> It is right, no matter the opcode length, the return address at 32bit os
>> should be 4 bytes.
>>
>> 2. esp+0x10 would hold the sixth parameter if it existed
>>
>> If it is fast call, it should be third parameter.
>>
>> Stack
>> =====================
>> esp + 0x14 : para 4(if existed)
>> esp + 0x10 : para 3
>> esp + 0x0c : return address
>> esp + 0x08 : ebx
>> esp + 0x04 : esi
>> esp + 0x00 : edi
>> =====================
>>
>> —
>> NTDEV is sponsored by OSR
>>
>> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>>
>> OSR is HIRING!! See http://www.osr.com/careers
>>
>> For our schedule of WDF, WDM, debugging and other seminars visit:
>> http://www.osr.com/seminars
>>
>> To unsubscribe, visit the List Server section of OSR Online at
>> http://www.osronline.com/page.cfm?name=ListServer
>>
>

> opps sorry for posting back to back hit enter too soon

your interpertation diagram is kinda wrong

always print / think /visialize /emphasize and dream stack position as
top to bottom
it makes concepts clear to self and to others

esp is always return address (WHEN YOU ARE ON FIRST INSTRUCTION in
ASSEMBLY MODE of a CALL (like Dr newcomer pointed out not when you
step in in c or higher level language using fancy studios)

parameter 0x1 is always esp+0x4
parameter 0x2 is always esp+0x8
parmater 0xN is always esp+ (0x4*0xN)

the ebx ecx whatever you posted will always be above return address

so if you are not first instruction but have stepped into the call 3
instructions
and if they were
push ebx
push esi
push edi

your stack will look like

esp +0x0 saved edi
esp+0x04 saved esi
esp+0x08 saved ebx
esp+0x0c return address
esp+0x10 param 1
esp+0x14 param 2

esp+0xNN param …

earlier data from parent calls or garbage
below this

and as Dr Newcomer rightly posted
write simple usermode application load it in a debugger and watch how
things appear
one visual is equivalent to ten dry books or 100 forum posts

write a simple foo.c
type WINAPI WinMain(…)
{
MessageboxA(…)
Exitprocess()
}

compile with cl /c o1 foo.c

Link with
link /ENTRY:WinMain foo.obj user32.lib kernel32.lib

But a console app doesn’t have a WinMain; only a GUI app has that. For
the OP’s purposes, a console app is a better choice, less rubbish to deal
with. So there would be no need to link with user32.lib.

since you define entrypoint all the c runtime codes will be bypassed
and disassembly will be relatively clear

And the C runtime will not be properly initialized; the command line will
not be parsed. And there is absolutely no gain in clarity of what is seen
for the actual experiment. This would largely be a waste of time.

load it in debugger set bp WinMain run

when you hit the breakpoint single step in from start till ExitProcess
you will learn much much much more than asking on this or any other forum

I have used the single-step technique many times to train people how to
read assembly code. As you say, direct experience is the best teacher.

On 8/9/13, raj_r wrote:
>>>>But I saw, the return address always be 4bytes, not only in your
>>>> example,
>>>> but other cases.
>>
>> yes on 32 bit it is always 4 bytes it is an address no other
>> interpretation exists
>>
>> ill try to make the statement a bit more clear as the good old doctor
>> also took a shot at it :slight_smile:
>>
>> call opcodes can be variable length
>>
>> so if a call was issued at 401000 with a 5 byte opcode sequence
>> the return address that will be pushed into stack will be 401005
>>
>> like wise if the call was issued with a 2 byte opcode sequence at 401000
>> the return address pushed will be 401002 and so on
>>
>> hope now the statement makes a bit more sense
>>
>>
>> -----> push :slight_smile: will drop down +0x04 on 32 bits per
>> push
>> =============== pop will make it come up
>> stack top esp+0x00 | | | 4 bytes per instruction in
>> 32
>> bit
>> | | |
>> | \ / |
>> | ^ _^ |
>> | | |
>> stack bot esp+0xNN | / |
>> ++++++++++
>>
>>
>>
>> On 8/9/13, workingmailing@163.com wrote:
>>> Thank you very much. raj.
>>>
>>> 1.
>>> depending on the length of opcodes return address will also vary in
>>> example above
>>>
>>> But I saw, the return address always be 4bytes, not only in your
>>> example,
>>> but other cases.
>>>
>>> It is right, no matter the opcode length, the return address at 32bit
>>> os
>>> should be 4 bytes.
>>>
>>> 2. esp+0x10 would hold the sixth parameter if it existed
>>>
>>> If it is fast call, it should be third parameter.
>>>
>>> Stack
>>> =====================
>>> esp + 0x14 : para 4(if existed)
>>> esp + 0x10 : para 3
>>> esp + 0x0c : return address
>>> esp + 0x08 : ebx
>>> esp + 0x04 : esi
>>> esp + 0x00 : edi
>>> =====================
>>>
>>> —
>>> NTDEV is sponsored by OSR
>>>
>>> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>>>
>>> OSR is HIRING!! See http://www.osr.com/careers
>>>
>>> For our schedule of WDF, WDM, debugging and other seminars visit:
>>> http://www.osr.com/seminars
>>>
>>> To unsubscribe, visit the List Server section of OSR Online at
>>> http://www.osronline.com/page.cfm?name=ListServer
>>>
>>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

> Thank you very much. raj.

depending on the length of opcodes return address will also vary in
example above

But I saw, the return address always be 4bytes, not only in your example,
but other cases.

It is right, no matter the opcode length, the return address at 32bit os
should be 4 bytes.

Yes, in Win32. In Win64, it is 64 bits, or 8 bytes.

  1. esp+0x10 would hold the sixth parameter if it existed

If it is fast call, it should be third parameter.

Stack

esp + 0x14 : para 4(if existed)
esp + 0x10 : para 3
esp + 0x0c : return address
esp + 0x08 : ebx
esp + 0x04 : esi
esp + 0x00 : edi

In modern compilers, if optimization is turned on, and LTCG is used, there
IS no standard calling convention. What appears in the source to be an
ordinary function call might find the first parameter in EAX and the
second parameter in EDX. Seriously. The compiler makes some very weird
choices. What we are always discussing here is the canonical linkages.
But LTCG (Link-Time Code Generation) means the compiler can look at every
call site and optimize the placement of parameters. And _thiscall (not
usually seen in the kernel) can be similarly warped. Trying to decode
Win64 code with LTCG enabled is incredibly challenging. Decoding Win32
code with full optimization and LTCG is not that much easier. So be
careful; after all the discussion about the canonical calling sequences,
the truth is vastly more complex.

There is a theory that if anyone ever understands the Universe, it will be
immediately destroyed and replaced by something far more complex. There
is another theory that this has already happened [Douglas Adams, in the
Hitch-hiker’s Guide to the Galaxy series]. The same can be said about
calling sequences.
joe


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

>There is a theory that if anyone ever understands the Universe, it will be immediately destroyed and replaced by something far more complex.

If you measure state of an isolated system, the measurement tool becomes part of the system, which is not isolated anymore… And if you measure quantum state, it gets destroyed…

>>There is a theory that if anyone ever understands the Universe, it will

> be immediately destroyed and replaced by something far more complex.

If you measure state of an isolated system, the measurement tool becomes
part of the system, which is not isolated anymore… And if you measure
quantum state, it gets destroyed…

Are you sure?

(And do you know what a Heisenbug is?)
joe


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer