Results 1 to 10 of 10

Thread: ASM assistance

  1. #1
    Administrator James's Avatar
    Join Date
    May 2010
    Location
    on the intraweb
    Posts
    3,180

    Default ASM assistance

    Trying to start a process called "Purge Process" programatically via triggering it through calling the offset.

    here is the function
    Code:
    01CAB314   .  55            PUSH EBP
    01CAB315   .  8BEC          MOV EBP,ESP
    01CAB317   .  83C4 F8       ADD ESP,-8
    01CAB31A   .  8955 F8       MOV DWORD PTR SS:[EBP-8],EDX
    01CAB31D   .  8945 FC       MOV DWORD PTR SS:[EBP-4],EAX
    01CAB320   .  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]
    01CAB323   .  80B8 E7030000>CMP BYTE PTR DS:[EAX+3E7],0
    01CAB32A   .  0F85 9E000000 JNZ MHC.01CAB3CE
    01CAB330   .  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]
    01CAB333   .  C680 E7030000>MOV BYTE PTR DS:[EAX+3E7],1
    01CAB33A   .  33C0          XOR EAX,EAX
    01CAB33C   .  55            PUSH EBP
    01CAB33D   .  68 C7B3CA01   PUSH MHC.01CAB3C7
    01CAB342   .  64:FF30       PUSH DWORD PTR FS:[EAX]
    01CAB345   .  64:8920       MOV DWORD PTR FS:[EAX],ESP
    01CAB348   .  B0 01         MOV AL,1
    01CAB34A   .  E8 15500A00   CALL MHC.01D50364
    01CAB34F   .  A1 9438FA01   MOV EAX,DWORD PTR DS:[1FA3894]
    01CAB354   .  8B00          MOV EAX,DWORD PTR DS:[EAX]
    01CAB356   .  E8 B1FE7DFE   CALL MHC.0048B20C
    01CAB35B   .  33C0          XOR EAX,EAX
    01CAB35D   .  55            PUSH EBP
    01CAB35E   .  68 A8B3CA01   PUSH MHC.01CAB3A8
    01CAB363   .  64:FF30       PUSH DWORD PTR FS:[EAX]
    01CAB366   .  64:8920       MOV DWORD PTR FS:[EAX],ESP
    01CAB369   .  E8 56260500   CALL MHC.01CFD9C4
    01CAB36E   .  33C9          XOR ECX,ECX
    01CAB370   .  8A15 D4B3CA01 MOV DL,BYTE PTR DS:[1CAB3D4]
    01CAB376   .  E8 4DF30500   CALL MHC.01D0A6C8
    01CAB37B   .  6A 00         PUSH 0                                   ; /Arg1 = 00000000                                            NOP This section
    01CAB37D   .  66:8B0D D8B3C>MOV CX,WORD PTR DS:[1CAB3D8]             ; |
    01CAB384   .  B2 02         MOV DL,2                                 ; |
    01CAB386   .  B8 E4B3CA01   MOV EAX,MHC.01CAB3E4                     ; |ASCII "Cached Patients Purge complete."
    01CAB38B   .  E8 20C57CFE   CALL MHC.004778B0                        ; \MHC.004778B0
    01CAB390   .  33C0          XOR EAX,EAX
    Here is some of my code:

    DWORD DetourPatchcall( PBYTE pSrc, PBYTE pDst, BOOL bForce )
    {
    DWORD dwOrgCallDest = 0;
    DWORD dwOldProtection = 0;
    DWORD dwRel = 0;


    if(!pSrc || !pDst)
    return (0);


    if( *pSrc == 0xE8 || bForce )
    {
    if( *pSrc == 0xE8 )
    {
    dwRel = *(DWORD*)( pSrc + 1 );
    dwOrgCallDest = ( (DWORD)pSrc + dwRel + 0x5 );
    }
    else
    {
    dwOrgCallDest = 1; // return 1 means no original call at pSrc
    }


    #ifdef WIN32

    if( !VirtualProtect( (PVOID)pSrc, 0x1000, PAGE_EXECUTE_READWRITE, &dwOldProtection ) )
    return (0);


    #else

    unprotect( GET_PAGE( pSrc ), 4096 );


    if ( ( ( (unsigned long)pSrc ) & 0xfff ) > 0xff9 )
    unprotect( GET_PAGE( pSrc + 4096 ), 4096 );

    #endif


    *pSrc = 0xE8;
    *( DWORD* )( pSrc + 1 ) = (DWORD)( pDst - pSrc - 5 );


    #ifdef WIN32
    VirtualProtect( (PVOID)pSrc, 0x1000, dwOldProtection, &dwOldProtection );
    #endif


    return dwOrgCallDest;
    }
    return (0);
    }



    void __stdcall callPatientPurge()
    {
    _asm
    {
    pushad
    pushfd
    mov al, 1
    mov ebx, 0x01D50364
    call ebx
    popfd
    popad
    }
    }


    Am I close?

  2. #2
    Über Prodigy & Developer Razo[R]apiD's Avatar
    Join Date
    May 2010
    Location
    Poland, Lublin
    Posts
    3,257

    Default

    You have to keep in mind that your injected DLL is in a separate thread and if your application is not thread-safe (supporting multi-threading), then you can break internal state of the application.

    It's the case with MoHAA, and many other games and apps. What you want to do to be 100% on the safe side, would be to make a detour in a function which handles a message-loop of application.

    Another thing you could do is to find a function which is periodically and often called, and just detour it, so your function calls just beofre or after it.


    If thread-safety is not your concern, you can run your function for your injected DLL directly.
    Make a typedef out of a function pointer, assign the address to it, and run.

  3. #3
    Administrator James's Avatar
    Join Date
    May 2010
    Location
    on the intraweb
    Posts
    3,180

    Default

    Thanks RR. I'm fairly certain it handles multithreading properly, however, what should I look for to be sure?

    Here's the dllmain

    // dllmain.cpp : Defines the entry point for the DLL application.
    #include "stdafx.h"
    #include "GlobalVariables.h"
    #include "SynchronizationProcess.h"
    #include "Login.h"


    DWORD WINAPI ThreadRoutine(LPVOID lpArg)
    {
    DWORD dwID = GetCurrentProcessId();


    while(1)
    {
    //Enumerate through all our window handles
    EnumWindows((WNDENUMPROC)WindowHandle, (LPARAM)dwID);


    //Check if our sync finished
    CheckIfSyncCompleted();


    Sleep(250);
    }
    }


    BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
    {
    HANDLE hHandles;


    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
    int *lpArgPtr;
    DWORD ThreadId;


    lpArgPtr = (int *)malloc(sizeof(int));
    hHandles = CreateThread(NULL, 0, ThreadRoutine, lpArgPtr, 0, &ThreadId);
    }
    break;


    case DLL_THREAD_ATTACH:
    {


    }
    break;


    case DLL_THREAD_DETACH:
    {


    }
    break;


    case DLL_PROCESS_DETACH:
    {


    }
    break;
    }
    return TRUE;
    }


    I'll try out the typedef routine and see if I can get that to work. Thanks


    EDIT:
    Does this look correct?

    typedef void (*MY_PatientPurge_t)();
    MY_PatientPurge_t MY_PatientPurge = (MY_PatientPurge_t)0x01CAB314;


    void PatientPurge()
    {
    MY_PatientPurge();
    }

  4. #4
    Über Prodigy & Developer Razo[R]apiD's Avatar
    Join Date
    May 2010
    Location
    Poland, Lublin
    Posts
    3,257

    Default

    Yep, looks correct. If it doesn't take any arguments, then yes Make sure you have valid calling convention (by default it's _cdecl, but your function can have another one)

  5. #5
    Administrator James's Avatar
    Join Date
    May 2010
    Location
    on the intraweb
    Posts
    3,180

    Default

    Here is the full function that controls the patient purge which is what I want to trigger

    01CAB314 . 55 PUSH EBP
    01CAB315 . 8BEC MOV EBP,ESP
    01CAB317 . 83C4 F8 ADD ESP,-8
    01CAB31A . 8955 F8 MOV DWORD PTR SS:[EBP-8],EDX
    01CAB31D . 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
    01CAB320 . 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
    01CAB323 . 80B8 E7030000>CMP BYTE PTR DS:[EAX+3E7],0
    01CAB32A . 0F85 9E000000 JNZ MHC.01CAB3CE
    01CAB330 . 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
    01CAB333 . C680 E7030000>MOV BYTE PTR DS:[EAX+3E7],1
    01CAB33A . 33C0 XOR EAX,EAX
    01CAB33C . 55 PUSH EBP
    01CAB33D . 68 C7B3CA01 PUSH MHC.01CAB3C7
    01CAB342 . 64:FF30 PUSH DWORD PTR FS:[EAX]
    01CAB345 . 64:8920 MOV DWORD PTR FS:[EAX],ESP
    01CAB348 . B0 01 MOV AL,1
    01CAB34A . E8 15500A00 CALL MHC.01D50364
    01CAB34F . A1 9438FA01 MOV EAX,DWORD PTR DS:[1FA3894]
    01CAB354 . 8B00 MOV EAX,DWORD PTR DS:[EAX]
    01CAB356 . E8 B1FE7DFE CALL MHC.0048B20C
    01CAB35B . 33C0 XOR EAX,EAX
    01CAB35D . 55 PUSH EBP
    01CAB35E . 68 A8B3CA01 PUSH MHC.01CAB3A8
    01CAB363 . 64:FF30 PUSH DWORD PTR FS:[EAX]
    01CAB366 . 64:8920 MOV DWORD PTR FS:[EAX],ESP
    01CAB369 . E8 56260500 CALL MHC.01CFD9C4
    01CAB36E . 33C9 XOR ECX,ECX
    01CAB370 . 8A15 D4B3CA01 MOV DL,BYTE PTR DS:[1CAB3D4]
    01CAB376 . E8 4DF30500 CALL MHC.01D0A6C8
    01CAB37B . 6A 00 PUSH 0 ; /Arg1 = 00000000
    01CAB37D . 66:8B0D D8B3C>MOV CX,WORD PTR DS:[1CAB3D8] ; |
    01CAB384 . B2 02 MOV DL,2 ; |
    01CAB386 . B8 E4B3CA01 MOV EAX,MHC.01CAB3E4 ; |ASCII "Cached Patients Purge complete."
    01CAB38B . E8 20C57CFE CALL MHC.004778B0 ; \MHC.004778B0
    01CAB390 . 33C0 XOR EAX,EAX
    01CAB392 . 5A POP EDX
    01CAB393 . 59 POP ECX
    01CAB394 . 59 POP ECX
    01CAB395 . 64:8910 MOV DWORD PTR FS:[EAX],EDX
    01CAB398 . 68 AFB3CA01 PUSH MHC.01CAB3AF
    01CAB39D > A0 04B4CA01 MOV AL,BYTE PTR DS:[1CAB404]
    01CAB3A2 . E8 816DDAFF CALL MHC.01A52128
    01CAB3A7 . C3 RETN
    01CAB3A8 .^ E9 CFA375FE JMP MHC.0040577C
    01CAB3AD .^ EB EE JMP SHORT MHC.01CAB39D
    01CAB3AF . 33C0 XOR EAX,EAX
    01CAB3B1 . 5A POP EDX
    01CAB3B2 . 59 POP ECX
    01CAB3B3 . 59 POP ECX
    01CAB3B4 . 64:8910 MOV DWORD PTR FS:[EAX],EDX
    01CAB3B7 . 68 CEB3CA01 PUSH MHC.01CAB3CE
    01CAB3BC > 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
    01CAB3BF . C680 E7030000>MOV BYTE PTR DS:[EAX+3E7],0
    01CAB3C6 . C3 RETN
    01CAB3C7 .^ E9 B0A375FE JMP MHC.0040577C
    01CAB3CC .^ EB EE JMP SHORT MHC.01CAB3BC
    01CAB3CE > 59 POP ECX
    01CAB3CF . 59 POP ECX
    01CAB3D0 . 5D POP EBP
    01CAB3D1 . C3 RETN


    After some digging, you were right it is a __cdecl, so I rewrote the function. Also it looks like it could have 3 parameters in the function. Here is my new function


    typedef void (__cdecl *MY_PatientPurge_t)(DWORD * x, DWORD * y, DWORD * z);
    MY_PatientPurge_t MY_PatientPurge = (MY_PatientPurge_t)0x01CAB314;


    void PatientPurge()
    {
    Sleep(5000);
    MY_PatientPurge((DWORD *)0x0616A9F0, (DWORD *)0x01CAB314, (DWORD *)0x01CAB314);
    }


    Now the values I'm passing through, are all DWORD PTR, and when I walk through each breakpoint during run time, here are the results

    EBP=0018FB9C


    ESP=0018FA6C
    EBP=0018FB9C


    ESP=0018FA6C


    EDX=0018FC98, (ASCII "Y")
    Stack SS:[0018FA64]=0040521C (MHC.0040521C)


    EAX=056D5AC0
    Stack SS:[0018FA68]=056D5AC0


    Stack SS:[0018FA68]=056D5AC0
    EAX=056D5AC0


    DS:[056D5EA7]=00
    Am I going about this the right way? My full code compiles and runs properly, but the PatientPurge() function doesn't seem to be triggered.

    EDIT:
    By the way, I put a message box right before executing the " MY_PatientPurge((DWORD *)0x0616A9F0, (DWORD *)0x01CAB314, (DWORD *)0x01CAB314);" and the messagebox comes up, so the function is being run, it's just not triggering the MY_PatientPurge()...


    EDIT2:
    Tried adjusting the code a bit, and got this:

    void __stdcall PatientPurge()
    {
    Sleep(5000);
    _asm
    {
    pushad
    pushfd
    mov ecx, 0x1CAB314
    call ecx
    popfd
    popad
    }
    }


    This got triggered and caused an exception error, however I got a little bit of info, just not sure if it'll be helpful.
    ---------------------------------------------------------------------------------------------------------
    2.1 Date : Tue, 17 Nov 2015 17:23:26 -0600
    2.2 Address : 01CAB323
    2.3 Module Name : MHC.exe - (Allscripts Homecare main application file)
    2.4 Module Version: 15.1.2.6
    2.5 Type : EAccessViolation
    2.6 Message : Access violation at address 01CAB323 in module 'MHC.exe'. Read of address 000003E7.
    2.7 ID : 9556
    2.8 Count : 1
    2.9 Status : New
    2.10 Note :
    On a seperate note, I went to that offset, and it crashed here

    01CAB323 . 80B8 E7030000>CMP BYTE PTR DS:[EAX+3E7],0

  6. #6

    Default

    Quote Originally Posted by James View Post
    On a seperate note, I went to that offset, and it crashed here

    01CAB323 . 80B8 E7030000>CMP BYTE PTR DS:[EAX+3E7],0
    It looks like EAX is set to a null pointer, either because of a NULL parameter or because the function is a fastcall, reading params from registers.
    You should check how other callee sets EAX or push values on the stack before calling the function from the hook.

  7. #7
    Administrator James's Avatar
    Join Date
    May 2010
    Location
    on the intraweb
    Posts
    3,180

    Default

    You're right. Here is a comparison
    Running with modified code:
    EBP=0B05FF88

    ESP=0B05FF4C
    EBP=0B05FF88

    ESP=0B05FF4C

    EDX=00000000
    Stack SS:[0B05FF44]=0B05FF04

    EAX=00000000
    Stack SS:[0B05FF48]=74F302BF (USER32.keybd_event)

    Stack SS:[0B05FF48]=00000000
    EAX=00000000

    DS:[000003E7]=???

    //=============================================

    Running normal patient purge:

    EBP=0018FB9C

    ESP=0018FA6C
    EBP=0018FB9C

    ESP=0018FA6C

    EDX=0018FC98, (ASCII "Y")
    Stack SS:[0018FA64]=0040521C (MHC.0040521C)

    EAX=05755AC0
    Stack SS:[0018FA68]=05755AC0

    Stack SS:[0018FA68]=05755AC0
    EAX=05755AC0
    So can I just do

    MOV EAX, 0x05755AC0

  8. #8

    Default


    mov eax, 0x05755AC0
    mov edx, 0x0018FC98


    ecx is not even used?

  9. #9
    Administrator James's Avatar
    Join Date
    May 2010
    Location
    on the intraweb
    Posts
    3,180

    Default

    First reference of ECX is here:

    01CAB36E . 33C9 XOR ECX,ECX


    EDIT:
    With those changes, it still crashes:


    void __stdcall PatientPurge()
    {
    Sleep(5000);


    _asm
    {
    pushad
    pushfd
    mov eax, 0x05755AC0
    mov edx, 0x0018FC98
    mov ecx, 0x01CAB314
    call ecx
    popfd
    popad
    }
    }


    Exception:
    ---------------------------------------------------------------------------------------------------------
    2.1 Date : Fri, 20 Nov 2015 15:44:37 -0600
    2.2 Address : 01CAB323
    2.3 Module Name : MHC.exe - (Allscripts Homecare main application file)
    2.4 Module Version: 15.1.2.6
    2.5 Type : EAccessViolation
    2.6 Message : Access violation at address 01CAB323 in module 'MHC.exe'. Read of address 05755EA7.
    2.7 ID : 9556
    2.8 Count : 1
    2.9 Status : New
    2.10 Note :

  10. #10

    Default

    It seems eax should be a pointer to a valid memory location.
    The value you set to eax is actually a pointer to a dynamic memory allocation, you should try to find somewhere how it allocate memory so that you can set eax to a proper value.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •