This is to save the value on the stack and continue to work with that value in further instruction(s) as already mentioned in the comments. This happens if no optimization is done.
You have to look at it separately.
Consider this in pseudocode.
var_4 = HeapAlloc()
func1(var_4)
Then the result would be similar to your assembler output namely:
1. call ds:HeapAlloc
2. mov [ebp+var_4], eax
3. mov eax, [ebp+var_4]
4. push eax
5. call func1
And in that case you are right, the value is still in eax
.
But now consider that:
var_4 = HeapAlloc()
between_func()
func1(var_4)
The assembler output would be similar to this
1. call ds:HeapAlloc
2. mov [ebp+var_4], eax
3. call between_func
4. mov eax, [ebp+var_4]
5. push eax
6. call func1
You can refer a pseudocode line to a section of the assembler code.
var_4 = HeapAlloc()
Corresponds to:
1. call ds:HeapAlloc
2. mov [ebp+var_4], eax
between_func()
Corresponds to:
3. call between_func
func1(var_4)
Corresponds to:
4. mov eax, [ebp+var_4]
5. push eax
6. call func1
And if you omit the between_func()
then you will get to the result you have. Concluded, the two instructions are compiled independently.