Firstly, let's understand what goes into edx. edx contains the first argument passed to this function which is a pointer the data that we want to compute its MD5 hash. Looking at images, stack frame of the current function is like:
esp + 0x0 --> | local_var_8 |
esp + 0x4 --> | local_var_4 |
esp + 0x8 --> | return_addr |
esp + 0xC --> | arg_0 |
At the beginning of the function, sub esp, 8 reserves 8 bytes on the stack for two local variables. Then you have the return address and arguments coming afterward. All those pushes that are used to pass arguments to CryptCreateHash will be poped back by that function before it returns to the current function, so the previous position of the stack will be preserved.
I believe true reverse engineering consists of understanding the code, not blind trace. Instead of tracing a value on the stack, it is better to look for the caller of this function, understand who has called this function and wherein the code is this function called, and then what is the parameter sent to this function.
Answering the second part of your question, you can customize breakpoints in IDA using some Python skills. You can create a conditional breakpoint for example and disable the break action as you have done. Whenever you hit this breakpoint, you can log the content of eip to find which instruction or wherein the code is this data accessed. If it is before this function, just log the data in, if it is after, you can enable break action again.
For that you need to consider some matters:
- You have to practice IDA python APIs. e.g. for getting a register content you have to call GetRegValue. This will help you to begin. Here also you can find the list of all IDA python APIs.
- If you set a breakpoint on a data that is passed to a lot of windows APIs such as crypt APIs, you will hit this breakpoint within a lot of library codes. Always look at the address space and if you are not inside your main program, skip them to avoid reversing library functions that are irrelevant to your main program.