@@ -24,8 +24,7 @@ impl Emu {
2424
2525 /// Call a 32bits function at addr, passing argument in an array of u64 but will cast to u32.
2626 /// The calling convention is stack, like winapi32.
27- pub fn call32 ( & mut self , addr : u64 , args : & [ u64 ] ) -> Result < u32 , MwemuError > {
28- //TODO: why this was u64?
27+ pub fn call32 ( & mut self , addr : u64 , args : & [ u32 ] ) -> Result < u32 , MwemuError > {
2928 if addr == self . regs ( ) . get_eip ( ) {
3029 if addr == 0 {
3130 return Err ( MwemuError :: new (
@@ -37,7 +36,7 @@ impl Emu {
3736 }
3837 let orig_stack = self . regs ( ) . get_esp ( ) ;
3938 for arg in args. iter ( ) . rev ( ) {
40- self . stack_push32 ( * arg as u32 ) ;
39+ self . stack_push32 ( * arg) ;
4140 }
4241 let ret_addr = self . regs ( ) . get_eip ( ) ;
4342 self . stack_push32 ( ret_addr as u32 ) ;
@@ -47,9 +46,9 @@ impl Emu {
4746 Ok ( self . regs ( ) . get_eax ( ) as u32 )
4847 }
4948
50- /// Call a 64bits function at addr, passing argument in an array of u64.
51- /// The calling convention is registers rcx/rdx/48 /r9 and then stack. Like windows64.
52- /// Dont use for linux64 syscall like convention, on those cases craft stack/register manually.
49+ /// Call 64bits function at addr using Microsoft x64 ABI , passing argument in an array of u64.
50+ /// The calling convention is registers rcx/rdx/r8 /r9 and then stack. Like windows64.
51+ /// Dont use for linux64 syscall like convention, for this is linux_call64()
5352 pub fn call64 ( & mut self , addr : u64 , args : & [ u64 ] ) -> Result < u64 , MwemuError > {
5453 if addr == self . regs ( ) . rip {
5554 if addr == 0 {
@@ -74,21 +73,109 @@ impl Emu {
7473 if n >= 4 {
7574 self . regs_mut ( ) . r9 = args[ 3 ] ;
7675 }
76+
77+ // stack pointer backup, for restoring when function returns.
7778 let orig_stack = self . regs ( ) . rsp ;
79+
80+ // padding
81+ let extra_args = if n > 4 { ( n - 4 ) * 8 } else { 0 } ;
82+ let total = extra_args + 32 + 8 ;
83+ let padding = ( 16 - ( self . regs ( ) . rsp as usize + total) % 16 ) % 16 ;
84+ self . regs_mut ( ) . rsp -= padding as u64 ;
85+
86+ // shadow space (32bits)
87+ for _ in 0 ..4 {
88+ self . stack_push64 ( 0 ) ;
89+ }
90+
91+ // stack parameters
7892 if n > 4 {
7993 for arg in args. iter ( ) . skip ( 4 ) . rev ( ) {
8094 self . stack_push64 ( * arg) ;
8195 }
8296 }
8397
98+ // return address
99+ let ret_addr = self . regs ( ) . rip ;
100+ self . stack_push64 ( ret_addr) ;
101+
102+ // trigger function
103+ self . regs_mut ( ) . rip = addr;
104+
105+ // emulate the function until return address is reached
106+ self . run ( Some ( ret_addr) ) ?;
107+
108+ // recover stack and return rax
109+ self . regs_mut ( ) . rsp = orig_stack;
110+ Ok ( self . regs ( ) . rax )
111+ }
112+
113+
114+ /// Call a 64bits function at addr, passing arguments in an array of u64.
115+ /// The calling convention is registers RDI, RSI, RDX, RCX, R8, R9 and then stack. Like linux64.
116+ pub fn linux_call64 ( & mut self , addr : u64 , args : & [ u64 ] ) -> Result < u64 , MwemuError > {
117+ if addr == self . regs ( ) . rip {
118+ if addr == 0 {
119+ return Err ( MwemuError :: new (
120+ "return address reached after starting the call64, change rip." ,
121+ ) ) ;
122+ } else {
123+ self . regs_mut ( ) . rip = 0 ;
124+ }
125+ }
126+
127+ let n = args. len ( ) ;
128+ if n >= 1 {
129+ self . regs_mut ( ) . rdi = args[ 0 ] ;
130+ }
131+ if n >= 2 {
132+ self . regs_mut ( ) . rsi = args[ 1 ] ;
133+ }
134+ if n >= 3 {
135+ self . regs_mut ( ) . rdx = args[ 2 ] ;
136+ }
137+ if n >= 4 {
138+ self . regs_mut ( ) . rcx = args[ 3 ] ;
139+ }
140+ if n >= 5 {
141+ self . regs_mut ( ) . r8 = args[ 4 ] ;
142+ }
143+ if n >= 6 {
144+ self . regs_mut ( ) . r9 = args[ 5 ] ;
145+ }
146+
147+ // stack pointer backup, for restoring when function returns.
148+ let orig_stack = self . regs ( ) . rsp ;
149+
150+ // padding
151+ let extra_args = if n > 6 { ( n - 6 ) * 8 } else { 0 } ;
152+ let total = extra_args + 8 ;
153+ let padding = ( 16 - ( self . regs ( ) . rsp as usize + total) % 16 ) % 16 ;
154+ self . regs_mut ( ) . rsp -= padding as u64 ;
155+
156+ // stack parameters
157+ if n > 6 {
158+ for arg in args. iter ( ) . skip ( 6 ) . rev ( ) {
159+ self . stack_push64 ( * arg) ;
160+ }
161+ }
162+
163+ // return address
84164 let ret_addr = self . regs ( ) . rip ;
85165 self . stack_push64 ( ret_addr) ;
166+
167+ // trigger function
86168 self . regs_mut ( ) . rip = addr;
169+
170+ // emulate the function until return address is reached
87171 self . run ( Some ( ret_addr) ) ?;
172+
173+ // recover stack and return rax
88174 self . regs_mut ( ) . rsp = orig_stack;
89175 Ok ( self . regs ( ) . rax )
90176 }
91177
178+
92179 /// Start emulation until a ret instruction is found.
93180 /// It will return the address or MwemuError.
94181 #[ inline]
0 commit comments