AutoHotkey Community

It is currently May 26th, 2012, 2:36 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 19 posts ]  Go to page Previous  1, 2

advice is best for end user programming
yes
no
You may select 1 option

View results
Author Message
 Post subject: advise after functions
PostPosted: January 24th, 2009, 9:58 pm 
Offline

Joined: August 3rd, 2007, 8:01 am
Posts: 555
Location: Houston, TX
Thanks Lexikos.
I made a couple of minor changes.

AdviseUDF:
now supports types: "before" and "after"
although after really means - just before first return line :(
if there is no return line in the advised function, unexpected things might happen.

Code:
advise(advice, type, advisee)
{
    static ACT_EXPRESSION:=3, _sizeof_FuncParam:=16, _Var_Name:=16
        , _JumpToLine:=4, _Param:=8, _ParamCount:=12, _MinParams:=16, _IsBuiltIn:=49
    LowLevel_init()
    ; Resolve functions and validate.
    if !(advice_func := __findFunc(advice))
        || !(advisee_func := __findFunc(advisee))
        || NumGet(advisee_func+_IsBuiltIn,0,"char")
        || (param_count := NumGet(advisee_func+_ParamCount)) < NumGet(advice_func+_MinParams)
        return false
    ; Begin generating code.
    cg := code_gen()
    ; Begin a standalone expression. Each standalone expression has only one arg.
    line := code_line(cg, ACT_EXPRESSION), code_arg(cg, 0, true)
    ; Begin function call by adding a function deref.
    code_arg_deref(cg, advice, advice_func, true, param_count)
    ; Write required text for a function call:
    code_arg_write(cg, "(")
    ; Get address of advisee's first parameter (FuncParam).
    param := NumGet(advisee_func+_Param)
    ; For each available parameter,
    Loop %param_count%
    {
        if A_Index > 1
            code_arg_write(cg, ",")
        ; Get Var of this FuncParam.
        param_var := NumGet(param+0)
        ; Add variable deref.
        code_arg_deref(cg, __str(NumGet(param_var+_Var_Name)), param_var, false)
        ; Move to next parameter. (OK if no next parameter; loop will terminate).
        param += _sizeof_FuncParam
    }
    code_arg_write(cg, ")")
    ; Finish generating code.


if (type = "after")
{
  line1 := Numget(advisee_func+_JumpToLine, 0, "UInt")
  loop
  {
  lineAct := NumGet(line1+0, 0, "UChar")
    if (lineAct != 102)
      line1 := Numget(line1+0, 20, "UInt")
    else
      break
  }
 
  {
    if (ch := code_finalize(cg))
    {
      ; Insert the code before the first return statement
      code_insert_before(ch, line1)
      code_delete_handle(ch)
    }
    code_gen_delete(cg)
    return !!ch
  }
}
else
{
    if (ch := code_finalize(cg))
    {
        ; Insert the code before the jump-to line of the function.
        code_insert_before(ch, NumGet(advisee_func+_JumpToLine))
        ; Re-target the function at the new line.
        NumPut(line, advisee_func+_JumpToLine)
        code_delete_handle(ch)
    }
    code_gen_delete(cg)
    return !!ch
  }
 
}



AdviseBIF: added paramter type := "before" | "after"

Code:
AdviseBIF(advisee, type, advice)
{
adviceInstruction := ""
. "B9" mcodeptr(RegisterCallback(advice,"Cdecl",4,1))    ; mov   ecx, ...
. "FFD1"          ; call  ecx
%type% := adviceInstruction
    __mcode(advisee, ""
    . "8B442404"      ; mov   eax,dword ptr [esp+4]
    . "8B08"          ; mov   ecx,dword ptr [eax]
    . "51"            ; push  ecx
    . "FF742410"      ; push  dword ptr [esp+10h]
    . "FF742410"      ; push  dword ptr [esp+10h]
    . "50"            ; push  eax
    . before
    . "B9" mcodeptr(NumGet(__findFunc(advisee)+4))    ; mov   ecx, ...
    . "FFD1"          ; call  ecx
    . after
    . "83C410"        ; add   esp,10h
    . "C3")           ; ret
}


Report this post
Top
 Profile  
Reply with quote  
PostPosted: January 25th, 2009, 5:29 pm 
Offline

Joined: August 3rd, 2007, 8:01 am
Posts: 555
Location: Houston, TX
Lexikos wrote:
:?
Code:
LowLevel_init()
AdviseBIF("VarSetCapacity","Debugger")
{...
AdviseBIF(advisee, advice)
{
    __mcode(advisee, ""
    . "8B442404"      ; mov   eax,dword ptr [esp+4]
    . "8B08"          ; mov   ecx,dword ptr [eax]
    . "51"            ; push  ecx
    . "FF742410"      ; push  dword ptr [esp+10h]
    . "FF742410"      ; push  dword ptr [esp+10h]
    . "50"            ; push  eax

    . "B9" mcodeptr(RegisterCallback(advice,"Cdecl",4,0))    ; mov   ecx, ...
    . "FFD1"          ; call  ecx
    . "B9" mcodeptr(NumGet(__findFunc(advisee)+4))    ; mov   ecx, ...
    . "FFD1"          ; call  ecx
    . "B9" mcodeptr(RegisterCallback(advice,"Cdecl",4,1))    ; mov   ecx, ...
    . "FFD1"          ; call  ecx

    . "83C410"        ; add   esp,10h
    . "C3")           ; ret
}

It seems that you need to add a parameter to the 3 params from
BuiltInFunctionType(ResultToken, Param, ParamCount)
to fill the params for
Debugger(aResultToken, aParam, aParamCount, aName)
Is the aName in ecx here?:
. "51" ; push ecx
What is in eax? before the calls?
I am still a little lost after reading:
http://www.rorydriscoll.com/2008/05/19/mockitnow-redirecting-function-calls-in-c/ and the LowLevel Reference chm file.

Lexikos: could you please help me understand your asm wizardry here?

Can this technique be used to hook c functions directly if you have pointers to them, rather than hooking dllcall?

Also, I have no idea even how to begin trying to understand this part from your DebugBIF in here: http://www.autohotkey.com/forum/topic36665.html&highlight=debugbif

Code:
if !VarSetCapacity(DebugErrorLevel)
    {
        VarSetCapacity(DebugErrorLevel, 56), NumPut(0xC35D5E5F, NumPut(0x10C4830C, NumPut(0x55FF5756, NumPut(0x1C75FF20, NumPut(0x75FF0E74, NumPut(0x3038800C, NumPut(0xC4830840, NumPut(0x8B08458B, NumPut(0x1055FF56, NumPut(0x1C75FF3E, NumPut(0x8B2075FF, NumPut(0x5718758B, NumPut(0x56EC8B55, NumPut(&DebugErrorLevel+4, DebugErrorLevel))))))))))))))
        VarSetCapacity(DebugResult, 60), NumPut(0x0000C35D, NumPut(0x5E5F10C4, NumPut(0x830855FF, NumPut(0x57561875, NumPut(0xFF1C75FF, NumPut(0x0E750038, NumPut(0x80068B15, NumPut(0x7500087E, NumPut(0x830CC483, NumPut(0x0C55FF56, NumPut(0x1875FF3E, NumPut(0x8B1C75FF, NumPut(0x5714758B, NumPut(0x56EC8B55, NumPut(&DebugResult+4, DebugResult)))))))))))))))
    }


Report this post
Top
 Profile  
Reply with quote  
PostPosted: January 25th, 2009, 6:35 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7502
Location: Australia
tinku99 wrote:
Is the aName in ecx here?:
. "51" ; push ecx
Yes, ecx contains a pointer to the function's name. This is passed via aResultToken.marker.
Quote:
What is in eax? before the calls?
The first instruction, mov eax ... puts the value of the aResultToken parameter into eax. The value of eax before the function begins is irrelevant.
Quote:
Lexikos: could you please help me understand your asm wizardry here?
I am not qualified to teach assembly, being only a beginner myself. I will attempt to explain:
Code:
; Put aResultToken into eax.
mov   eax,dword ptr [esp+4]
; Put aResultToken.marker into ecx.
mov   ecx,dword ptr [eax]
; Push parameters, right to left.
push  ecx                   ; aName
push  dword ptr [esp+10h]   ; aParamCount
push  dword ptr [esp+10h]   ; aParam
push  eax                   ; aResultToken

; Calls to absolute addresses must be done indirectly, using a register.
; Because all three are CDECL, each call may use what we prepared above.
; In theory this works, HOWEVER, the compiler may optimize by using the
; parameters as local variables. In such a case, advice_callback1 would
; receive garbage parameters. Testing showed this happens with DllCall
; on beta builds in VC++ 2008. This is why DebugBIF does not use this method.

; Call first callback.
mov   ecx, advice_callback0
call  ecx
; Call built-in function.
mov   ecx, advisee_bif
call  ecx
; Call second callback.
mov   ecx, advice_callback1
call  ecx

; Pop parameters off stack.
add   esp,10h
ret

Quote:
Can this technique be used to hook c functions directly if you have pointers to them, rather than hooking dllcall?
Not exactly; in this case we can overwrite the pointer AutoHotkey uses to call the function. To redirect an arbitrary C function, you would need to overwrite the code of the function itself. This would have additional complications which I'm not interested in exploring.

Quote:
Also, I have no idea even how to begin trying to understand this part from your DebugBIF in here: http://www.autohotkey.com/forum/topic36665.html&highlight=debugbif
I'm not surprised. The inner-most call, NumPut(&Debug...+4, Debug...), stores a pointer to the actual machine code in the first 4 bytes of the variable. Working outward from there, machine code is written to the variable 4 bytes at a time. More importantly, I've updated the DebugBIF thread with the original C++ source code.


Report this post
Top
 Profile  
Reply with quote  
 Post subject: UDF hooks for 1.0.48
PostPosted: April 19th, 2009, 5:35 am 
Offline

Joined: August 3rd, 2007, 8:01 am
Posts: 555
Location: Houston, TX
I finally got around to try to update the user defined advice functions... here is a humble first attempt:
it is requiring an advising label...

Code:
; adviseUDF by Naveen Garg for 1.0.48+
;; modified from advise(...) by Lexikos for 1.0.47
;; http://www.autohotkey.com/forum/profile.php?mode=viewprofile&u=3754
;; copyright http://www.autohotkey.com/forum/topic39287.html?sid=241caa966a8fdc2921188706f5213cb0

adviseUDF(advice, type, advisee)  ; type = before or after
{
    static ACT_EXPRESSION:=3, _sizeof_FuncParam:=16, _Var_Name:=24
        , _JumpToLine:=4, _Param:=8, _ParamCount:=12, _MinParams:=16, _IsBuiltIn:=49
    ; advice uses same parameters advisee
    LowLevel_init()
    ; Resolve functions and validate.
    if !(advice_func := __findFunc(advice))
        || !(advisee_func := __findFunc(advisee))
        || NumGet(advisee_func+_IsBuiltIn,0,"char")
        || (param_count := NumGet(advisee_func+_ParamCount)) < NumGet(advice_func+_MinParams)
        return false
    ; Begin generating code.
    cg := code_gen()

    ; Begin a standalone expression. Each standalone expression has only one arg.
line := code_line(cg, ACT_GOSUB := 96) 
code_arg(cg, 0, false)
code_arg_write(cg, advice)

if (type = "after")
{
  line1 := Numget(advisee_func+_JumpToLine, 0, "UInt")
  loop
  {
  lineAct := NumGet(line1+0, 0, "UChar")
    if (lineAct != 102)
      line1 := Numget(line1+0, 20, "UInt")
    else
      break
  }
 
  {
    if (ch := code_finalize(cg))
    {
      ; Insert the code before the first return statement
      code_insert_before(ch, line1)
      code_delete_handle(ch)
    }
    code_gen_delete(cg)
    return !!ch
  }
}
else
{
    if (ch := code_finalize(cg))
    {
        ; Insert the code before the jump-to line of the function.
        code_insert_before(ch, NumGet(advisee_func+_JumpToLine))
        ; Re-target the function at the new line.
        NumPut(line, advisee_func+_JumpToLine)
        code_delete_handle(ch)
    }
    code_gen_delete(cg)
    return !!ch
  }
 
}





testscript:
Code:
myFunc("Apple","banana")
adviseUDF("myFuncAdvice","before","myFunc")
myFunc("Apple","banana")
return

myFunc(A,B) {
    MsgBox %A%, meet %B%.
return
}

SwapParameters(ByRef A, ByRef B) {
    C := A
    A := RegExReplace(B,"^\w","$U0")
    B := RegExReplace(C,"^\w","$l0")
}

myFuncAdvice:
myFuncAdvice("myFunc")
return

myFuncAdvice(advisee)
{
    static ACT_EXPRESSION:=3, _sizeof_FuncParam:=16, _Var_Name:=24
        , _JumpToLine:=4, _Param:=8, _ParamCount:=12, _MinParams:=16, _IsBuiltIn:=49
    ; advice uses same parameters advisee
    LowLevel_init()
    ; Resolve functions and validate.
    if  !(advisee_func := __findFunc(advisee))
        || NumGet(advisee_func+_IsBuiltIn,0,"char")
    return false
    param_count := NumGet(advisee_func+_ParamCount)
    param := NumGet(advisee_func+_Param)
    ; For each available parameter,
    Loop %param_count%
    {
        ; Get Var of this FuncParam.
        param_var := NumGet(param+0)
        ; Add variable deref.
   msgbox % __str(NumGet(param_var+_Var_Name))
   msgbox % __str(NumGet(param_var + 8))

        code_arg_deref(cg, __str(NumGet(param_var+_Var_Name)), param_var, false)
        ; Move to next parameter. (OK if no next parameter; loop will terminate).
        param += _sizeof_FuncParam
    }

msgbox, advised
}

!q::ExitApp
!r::Reload
#Include adviseUDF.ahk  ;v1.0.48
#Include ..\import
#Include Lowlevel.ahk  ; v1.0.48
#Include code.ahk  ; v1.0.48



Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 19 posts ]  Go to page Previous  1, 2

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 3 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group