If the convention call uses the stack (as it seems) to pass parameters, you can figure out how many parameters and what size they have.
For "how many", you can look at the operand of the RET instruction, if any (stdcall convention). This will give you how many bytes parameters are using. Of course this data alone if of not much use.
You have to read the function code and search for memory references like this [EBP+n] where n is a positive offset from the value of EBP. Positive offsets are addressing parameters, and negative offsets are addressing local variables (created with the SUB ESP,x instruction)
Hopefully, you will able to spot all distinct parameters. If the function has been complied with optimizations, this may be hard to figure out.
For size and type, more inverse engineering is needed. Look at the instructions that use addressed parameters. If you find something like dword ptr [ebp+n]
then that parameter is 32-bit long. word ptr [ebp+n]
tels you that the parameter is 16-bit long, and byte ptr [ebp+n]
means a byte size parameter.
For byte and word sized parameters, the most plausible options are char/unsigned char
and short/unsigned short
.
For double word sized parameters, type may be int/unsigned int/long/unsigned long
, but it may be a pointer as well. To differentiate a pointer from a plain integer, you will have to look further, to see if the dword read from the parameter is being used as a memory address itself to access memory (i.e. it's being dereferenciated).
To tell signedness of a parameter, you have to search for a code fragment in which a particular parameter is compared against some other value, and then a conditional jump is issued. The particular condition used in the jump will tell you if the comparison was performed taking the sign into account or not. For example: a comparison with a JA
/ JB
/ JAE
/ JBE
conditional jumps indicate an unsigned comparison and hence, an unsigned parameter. Conditional jumps as JG
/ JE
/ JGE
/ JLE
indicate signed parameter involved in the comparison.