Guest User

Untitled

a guest
Aug 29th, 2012
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.42 KB | None | 0 0
  1. /* loops through the import table of a DLL, if the target import func is found
  2.   it will be replaced, if OldFunc not null, old func ptr will be placed in OldFunc
  3.   on failure returns FALSE and error is in GLR */
  4. static BOOL PatchIAT(pTHX_ PIMAGE_DOS_HEADER dosHeader, SV * ImportDllName,
  5.     SV * ImportFunctionName, void ** oldFunc, void * newFunc){
  6. #define APPRVA2ABS(x) ((DWORD_PTR)dosHeader + (DWORD_PTR)(x))
  7.     if( dosHeader
  8.     && !IsBadReadPtr(dosHeader, sizeof(*dosHeader))
  9.     && dosHeader->e_magic == IMAGE_DOS_SIGNATURE){
  10.         PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)APPRVA2ABS(dosHeader->e_lfanew);
  11.         if( ntHeader
  12.         && !IsBadReadPtr(ntHeader, sizeof(*ntHeader))
  13.         && ntHeader->Signature == IMAGE_NT_SIGNATURE
  14.         //not a OBJ file, bug below if some of the entrys are not present?
  15.         && ntHeader->FileHeader.SizeOfOptionalHeader >= sizeof(IMAGE_OPTIONAL_HEADER)
  16.         && ntHeader->OptionalHeader.NumberOfRvaAndSizes >= IMAGE_DIRECTORY_ENTRY_IMPORT+1
  17.         ){
  18.             DWORD pDataDirImportRVA = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  19.             DWORD pDataDirImportSize = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
  20.             PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)APPRVA2ABS(pDataDirImportRVA);
  21.             if(pDataDirImportSize
  22.                && pDataDirImportRVA
  23.                && !IsBadReadPtr(importDescriptor, pDataDirImportSize)){
  24. STRLEN DllNameLen;
  25. char * DllNameStr = SvPV(ImportDllName, DllNameLen);
  26. while (importDescriptor->Name != 0){
  27.     const char * const TargetDllNameStr = (char *)APPRVA2ABS(importDescriptor->Name);
  28.     const int TargetDllNameLen = lstrlenA(TargetDllNameStr);
  29.     Perl_warn(aTHX_ "app import dep dll name is %s\n", TargetDllNameStr);
  30.     if(TargetDllNameLen == 0) goto NO_MORE_LIBS;
  31.     if(TargetDllNameLen == DllNameLen
  32.         && strnicmp(TargetDllNameStr, DllNameStr, TargetDllNameLen) == 0
  33.         && importDescriptor->OriginalFirstThunk
  34.         && importDescriptor->FirstThunk
  35.     ){
  36.         PIMAGE_THUNK_DATA OriginalFirstThunk = (PIMAGE_THUNK_DATA)APPRVA2ABS(importDescriptor->OriginalFirstThunk);
  37.         void ** FirstThunk = (void**)APPRVA2ABS(importDescriptor->FirstThunk);
  38. /*note only the first slice in the array is probed, they others should be valid if the 1st one is*/
  39.         if(! IsBadReadPtr(OriginalFirstThunk, sizeof(IMAGE_THUNK_DATA))
  40.            && ! IsBadReadPtr(FirstThunk, sizeof(void *))){
  41.             STRLEN FunctionNameLen;
  42.             char * FunctionNameStr = SvPV(ImportFunctionName, FunctionNameLen);
  43.             while(OriginalFirstThunk->u1.ForwarderString != 0){
  44.                 PIMAGE_IMPORT_BY_NAME TargetImport = (PIMAGE_IMPORT_BY_NAME)APPRVA2ABS(OriginalFirstThunk->u1.ForwarderString);    
  45.                 char * TargetFunctionNameStr = TargetImport->Name;
  46.                 int TargetFunctionNameLen = lstrlenA(TargetFunctionNameStr);
  47.                 Perl_warn(aTHX_ "app import dep func name is %s\n", TargetFunctionNameStr);
  48.                 if(TargetFunctionNameLen == FunctionNameLen
  49.                    && memcmp(TargetFunctionNameStr, FunctionNameStr, TargetFunctionNameLen) == 0){
  50.                     if(oldFunc) *oldFunc = *FirstThunk;
  51.                     *FirstThunk = newFunc;
  52.                     return TRUE;
  53.                 }
  54.                 OriginalFirstThunk++;
  55.                 FirstThunk++;
  56.             }
  57.         }
  58.         SetLastError(ERROR_PROC_NOT_FOUND);
  59.         goto ERROR;
  60.     }
  61.     importDescriptor++;
  62. }
  63.     NO_MORE_LIBS:
  64.     SetLastError(ERROR_MOD_NOT_FOUND);
  65.     goto ERROR;
  66. }
  67. }
  68. }
  69.     SetLastError(ERROR_BAD_EXE_FORMAT);
  70.     ERROR:
  71.     return FALSE;
  72. #undef APPRVA2ABS
  73. }
  74.  
  75. MODULE = Win32::API::Callback   PACKAGE = Win32::API::Callback::IATPatch
  76.  
  77. void
  78. new(classSV, callback, HookDll, ImportDllName, ImportFunctionName)
  79.     SV * classSV
  80.     W32AC_T * callback
  81.     SV * HookDll
  82.     SV * ImportDllName
  83.     SV * ImportFunctionName
  84. PREINIT:
  85.     PIMAGE_DOS_HEADER dosHeader;
  86.     HV * returnHV;
  87.     void * oldFunction;
  88. PPCODE:
  89.     SvGETMAGIC(HookDll);
  90.     if(SvPOK(HookDll)){
  91.         dosHeader = (PIMAGE_DOS_HEADER) GetModuleHandle(SvPV_nomg_nolen(HookDll));
  92.         if(!dosHeader) goto ERROR;
  93.     }
  94.     else{ dosHeader = (PIMAGE_DOS_HEADER) SvIV_nomg(HookDll);}
  95.     if(!PatchIAT(aTHX_ dosHeader, ImportDllName, ImportFunctionName,
  96.         &oldFunction, (void *)SvUVX(*hv_fetch(callback, "code", sizeof("code")-1, 0)))){
  97.         ERROR:
  98.         PUSHs(&PL_sv_undef);
  99.         PUTBACK;
  100.         return;    
  101.     }
  102.     returnHV = newHV();
  103.     //save the hmod, not dll str name, other dlls with same name might have been
  104.     //loaded in the meantime/sxs/etc
  105.     hv_store(returnHV,  "HookDllHmod",          sizeof("HookDllHmod")-1,
  106.                         newSVuv((UV)dosHeader), 0);
  107.     hv_store(returnHV,  "OrigFunc",             sizeof("OrigFunc")-1,
  108.                         newSVuv((UV)oldFunction) ,  0);
  109.     hv_store(returnHV,  "ImportDllName",        sizeof("ImportDllName")-1,
  110.                         newSVsv(ImportDllName), 0);
  111.     hv_store(returnHV,  "ImportFunctionName",   sizeof("ImportFunctionName")-1,
  112.                         newSVsv(ImportFunctionName), 0);
  113.     hv_store(returnHV,  "callback",             sizeof("callback")-1,
  114.                         newRV_inc((SV*)callback),    0);
  115.     mPUSHs(sv_bless(newRV_noinc((SV*)returnHV),
  116.                     gv_stashsv(classSV,0)
  117.                     )
  118.            );
  119.  
  120.  
  121. void
  122. Unpatch(...)
  123. PREINIT:
  124.     I32 flagvar = 1; /*no param default is to restore*/
  125.     SV * OrigFuncSV;
  126.     void * OrigFunc;
  127.     HV * self;
  128. PPCODE:
  129.     if (items < 1 || items > 2)
  130.        croak_xs_usage(cv, "self [, flag=true]");
  131.     else if(items == 2){
  132.         flagvar = sv_true(ST(1));
  133.     }
  134.     {SV * TmpRV = ST(0);
  135.     if (SvROK(TmpRV) && sv_derived_from(TmpRV, "Win32::API::Callback::IATPatch")) {
  136.         self = (HV*)SvRV(TmpRV);
  137.     }
  138.     else
  139.         Perl_croak(aTHX_ "%s: %s is not of type %s",
  140.             "Win32::API::Callback::IATPatch::Unpatch",
  141.             "self", "Win32::API::Callback::IATPatch");};
  142.     OrigFuncSV = *hv_fetch(self, "OrigFunc", sizeof("OrigFunc")-1, 0);
  143.     if(flagvar){
  144.     if(OrigFunc = (void *)SvUVX(OrigFuncSV)){
  145.         if(!PatchIAT(aTHX_
  146.             (PIMAGE_DOS_HEADER)SvUVX(*hv_fetch(self, "HookDllHmod", sizeof("HookDllHmod")-1, 0)),
  147.             *hv_fetch(self, "ImportDllName", sizeof("ImportDllName")-1, 0),
  148.             *hv_fetch(self, "ImportFunctionName", sizeof("ImportFunctionName")-1, 0),
  149.             NULL,       OrigFunc
  150.         )){
  151.             goto FAILED;
  152.         }
  153.         else goto SUCCESS;
  154.     }
  155.     else SetLastError(ERROR_NO_MORE_ITEMS);
  156.     }
  157.     else{ //flag is false, never restore original function
  158.     SUCCESS:
  159.         sv_setuv(OrigFuncSV, 0);
  160.         PUSHs(&PL_sv_yes);
  161.         PUTBACK;
  162.         return;
  163.     }
  164.     FAILED:
  165.     PUSHs(&PL_sv_undef);
  166.  
  167. void
  168. DESTROY(self)
  169.     SV * self
  170. PREINIT:
  171.     SV * retsv;
  172. PPCODE:
  173.     PUSHMARK(SP);
  174.     PUSHs(self);
  175.     PUSHs(&PL_sv_yes);
  176.     PUTBACK;
  177.     XS_Win32__API__Callback__IATPatch_Unpatch(aTHX_ cv); /*the cv is wrong with this hack*/
  178.     //call_pv("Win32::API::Callback::IATPatch::Unpatch", 0);
  179.     retsv = POPs;
  180.     if(!sv_true(retsv) /*ERROR_NO_MORE_ITEMS means it was already unpatched*/
  181.        && GetLastError() != ERROR_NO_MORE_ITEMS){
  182.         croak("%s: Failed to unpatch DLL, error number %u ",
  183.               "Win32::API::Callback::IATPatch::DESTROY", GetLastError());
  184.     }
  185.  
  186. # GetOriginalFunction is reserved for future
  187. # GetOriginalFunction should return a fully working Win32::API obj that calls
  188. # the original function, the prototype should be obtained automatically from the
  189. # Win32::API::Callback obj
  190.  
  191. void
  192. GetOriginalFunctionPtr(self)
  193. W32ACIATP_T * self
  194. PPCODE:
  195.     mPUSHs(newSVsv(*hv_fetch(self, "OrigFunc", sizeof("OrigFunc")-1, 0)));
  196.  
  197.  
  198. void
  199. CLONE_SKIP(...)
  200. PPCODE:
  201. /* Prevent double unpatching from a fork. I dont think it makes sense to clone
  202.   IATPatches, there is only one DLL per process. You can't have 2 different
  203.   patches on it and have 2 different hooks expect to work based on the calling
  204.   psuedo process. Well you could have a aTHX based dispatcher that will look up
  205.   the correct weak ref ::Callback HV to use each time the PerlCallback() is
  206.   called, but that is s alot of work for little gain. Currently the HV * of
  207.   the ::Callback is hard coded into the ASM callback, and that HV * is interp
  208.   specific.
  209. */
  210.     XPUSHs(&PL_sv_yes);
Advertisement
Add Comment
Please, Sign In to add comment