PageRenderTime 32ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/ITH2/ITH64/ITH_DLL/texthook.cpp

http://interactive-text-hooker.googlecode.com/
C++ | 679 lines | 621 code | 17 blank | 41 comment | 99 complexity | 08ce82aa2834c21c276e528095e46714 MD5 | raw file
Possible License(s): GPL-3.0
  1. /* Copyright (C) 2010-2011 kaosu (qiupf2000@gmail.com)
  2. * This file is part of the Interactive Text Hooker.
  3. * Interactive Text Hooker is free software: you can redistribute it and/or
  4. * modify it under the terms of the GNU General Public License as published
  5. * by the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. * You should have received a copy of the GNU General Public License
  12. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include "utility.h"
  15. TextHook *hookman,*current_available;
  16. FilterRange filter[8];
  17. static const int size_hook=sizeof(TextHook);
  18. UINT_PTR flag, enter_count;
  19. //provide const time hook entry.
  20. #define HOOK_DEBUG_HEAD 0
  21. static int userhook_count;
  22. static const BYTE common_prologue[]={
  23. 0x48, 0x89, 0x04, 0xE4, //mov [rsp], rax
  24. //Save flag (prgram status).
  25. 0x9C, //pushfq
  26. //Save volatile registers.
  27. 0x51, 0x52, //push rcx,rdx
  28. 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, 0x53, //push r8~r11
  29. };
  30. static const BYTE common_epilogue[]={
  31. 0x41, 0x5B, 0x41, 0x5A, 0x41, 0x59, 0x41, 0x58, //pop r11~r8
  32. 0x5A, 0x59, //pop rdx,rcx
  33. //Restore flag (program status).
  34. 0x9D, //popfq
  35. 0x58 //pop rax
  36. };
  37. static const BYTE common_route[]={
  38. 0x48, 0x8B, 0xD4, //mov rdx,rsp; param 1, stack
  39. 0x48, 0x83, 0xC2, 0x40, //add rdx,0x40
  40. 0x48, 0x83, 0xEC, 0x20, //sub rsp,0x20, allocate stack
  41. 0x48, 0xB8, 0,0,0,0,0,0,0,0, //mov rax, @hook, 0x2D
  42. 0x48, 0xB9, 0,0,0,0,0,0,0,0, //mov rcx, this, 0x37
  43. 0xFF, 0xD0, //call rax
  44. 0x48, 0x83, 0xC4, 0x20, //add rsp,0x20, restore stack
  45. };
  46. #define PROLOGUE_LENGTH (sizeof(common_prologue))
  47. #define EPILOGUE_LENGTH (sizeof(common_epilogue))
  48. #define ROUTE_LENGTH (sizeof(common_route))
  49. //copy original instruction
  50. //jmp back
  51. void SectionRelayBuffer::Release()
  52. {
  53. UINT_PTR i;
  54. UINT_PTR size;
  55. LPVOID addr;
  56. for (i=0;i<section_count;i++)
  57. {
  58. size=0;
  59. addr=(LPVOID)record[i].section_relay_buffer;
  60. NtFreeVirtualMemory(NtCurrentProcess(),&addr,&size,MEM_RELEASE);
  61. }
  62. }
  63. UINT_PTR SectionRelayBuffer::RegisterSection(UINT_PTR section)
  64. {
  65. UINT_PTR i;
  66. UINT_PTR base=(UINT_PTR)(section)>>31;
  67. for (i=0;i<section_count;i++)
  68. if (record[i].section_register==base) break;
  69. if (i<section_count)
  70. {
  71. record[i].section_referenced++;
  72. return record[i].section_relay_buffer;
  73. }
  74. UINT_PTR addr=(base<<31)+0x40000000;
  75. UINT_PTR size=0x1000,len;
  76. LPVOID allocate;
  77. MEMORY_BASIC_INFORMATION info;
  78. allocate=(LPVOID)addr;
  79. for (;;)
  80. {
  81. allocate=(LPVOID)addr;
  82. NtQueryVirtualMemory(NtCurrentProcess(),allocate,
  83. MemoryBasicInformation,&info,sizeof(info),&len);
  84. if ((info.State&MEM_FREE))
  85. if ((UINT_PTR)info.BaseAddress+info.RegionSize-addr>=0x1000)
  86. break;
  87. addr=(UINT_PTR)info.BaseAddress-0x1000;
  88. }
  89. NtAllocateVirtualMemory(NtCurrentProcess(),&allocate,
  90. 0,&size,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
  91. addr=(UINT_PTR)allocate;
  92. record[section_count].section_register=section>>31;
  93. record[section_count].section_relay_buffer=addr;
  94. record[section_count].section_referenced=1;
  95. section_count++;
  96. return addr;
  97. }
  98. BOOL SectionRelayBuffer::UnregisterSection(UINT_PTR section)
  99. {
  100. UINT_PTR i,base=section>>31;
  101. for (i=0;i<section_count;i++)
  102. {
  103. if (record[i].section_register==section)
  104. {
  105. record[i].section_referenced--;
  106. if (record[i].section_referenced==0)
  107. {
  108. LPVOID addr=(LPVOID)(record[i].section_relay_buffer);
  109. UINT_PTR size=0x1000;
  110. NtFreeVirtualMemory(NtCurrentProcess(),&addr,&size,MEM_RELEASE);
  111. for (;i<section_count;i++)
  112. record[i]=record[i+1];
  113. section_count--;
  114. }
  115. return TRUE;
  116. }
  117. }
  118. return FALSE;
  119. }
  120. extern "C" UINT_PTR GetModuleBaseByHash(UINT_PTR hash);
  121. inline UINT_PTR GetModuleBase(UINT_PTR hash)
  122. {
  123. return GetModuleBaseByHash(hash);
  124. }
  125. void NotifyHookInsert()
  126. {
  127. if (live)
  128. {
  129. BYTE buffer[0x10];
  130. *(UINT_PTR*)buffer=-1;
  131. *(UINT_PTR*)(buffer+8)=1;
  132. IO_STATUS_BLOCK ios;
  133. NtWriteFile(hPipe,0,0,0,&ios,buffer,HEADER_SIZE,0,0);
  134. }
  135. }
  136. typedef void (*DataFun)(UINT_PTR, const HookParam&, UINT_PTR*, UINT_PTR*, UINT_PTR*);
  137. bool HookFilter(UINT_PTR retn)
  138. {
  139. UINT_PTR i;
  140. for (i=0;filter[i].lower;i++)
  141. if (retn>filter[i].lower&&retn<filter[i].upper) return true;
  142. return false;
  143. }
  144. #define SMALL_BUFF_SIZE 0x40
  145. typedef void (TextHook::*sendfun)(UINT_PTR,UINT_PTR,UINT_PTR);
  146. void TextHook::Send(UINT_PTR stack_ptr, UINT_PTR data, UINT_PTR split)
  147. {
  148. __try
  149. {
  150. UINT_PTR dwCount,dwAddr;
  151. BYTE *pbData, pbSmallBuff[SMALL_BUFF_SIZE];
  152. UINT_PTR dwType=hp.type;
  153. UINT_PTR dwRetn=*(UINT_PTR*)stack_ptr;
  154. if (live)
  155. {
  156. if ((dwType&NO_CONTEXT)==0)
  157. if (HookFilter(dwRetn)) return;
  158. dwCount=-1;
  159. dwAddr=hp.addr;
  160. if (trigger)
  161. {
  162. //MessageBox(0,0,0,0);
  163. trigger=0;
  164. //InsertDynamicHook((LPVOID)dwAddr,*(UINT_PTR*)(dwDataBase-0x1C),*(UINT_PTR*)(dwDataBase-0x18));
  165. }
  166. if (dwType&EXTERN_HOOK)
  167. {
  168. /*DataFun fun=(DataFun)hp.extern_fun;
  169. if (fun) fun(dwDataBase,hp,&data,&split,&dwCount);
  170. else dwCount=0;
  171. if (dwCount==0) return;*/
  172. }
  173. else
  174. {
  175. if (data==0) return;
  176. if (dwType&USING_SPLIT)
  177. {
  178. if (dwType&SPLIT_INDIRECT) split=*(UINT_PTR*)(split+hp.split_ind);
  179. }
  180. else split=0;
  181. if (dwType&DATA_INDIRECT)
  182. {
  183. data=*(UINT_PTR*)(data+hp.ind);
  184. }
  185. if (dwType&PRINT_DWORD)
  186. {
  187. swprintf((WCHAR*)(pbSmallBuff+HEADER_SIZE),L"%.8X ",data);
  188. data=(UINT_PTR)pbSmallBuff+HEADER_SIZE;
  189. }
  190. dwCount=GetLength(stack_ptr, data);
  191. }
  192. if (dwCount+HEADER_SIZE>=SMALL_BUFF_SIZE) pbData=new BYTE[dwCount+HEADER_SIZE];
  193. else pbData=pbSmallBuff;
  194. if (hp.length_offset==1)
  195. {
  196. if (dwType&STRING_LAST_CHAR)
  197. {
  198. LPWSTR ts=(LPWSTR)data;
  199. data=ts[wcslen(ts)-1];
  200. }
  201. data&=0xFFFF;
  202. if (dwType&BIG_ENDIAN)
  203. if (data>>8)
  204. data=_byteswap_ushort(data&0xFFFF);
  205. if (dwCount==1) data&=0xFF;
  206. *(WORD*)(pbData+HEADER_SIZE)=data&0xFFFF;
  207. }
  208. else memcpy(pbData+HEADER_SIZE,(void*)data,dwCount);
  209. *(UINT_PTR*)pbData=dwAddr;
  210. if (dwType&NO_CONTEXT) dwRetn=0;
  211. *((UINT_PTR*)pbData+1)=dwRetn;
  212. *((UINT_PTR*)pbData+2)=split;
  213. if (dwCount)
  214. {
  215. IO_STATUS_BLOCK ios={};
  216. if (STATUS_PENDING==NtWriteFile(hPipe,0,0,0,&ios,pbData,dwCount+HEADER_SIZE,0,0))
  217. {
  218. NtWaitForSingleObject(hPipe,0,0);
  219. NtFlushBuffersFile(hPipe,&ios);
  220. }
  221. }
  222. if (pbData!=pbSmallBuff) delete pbData;
  223. }
  224. }
  225. __except(EXCEPTION_EXECUTE_HANDLER)
  226. {
  227. OutputConsole(L"except");
  228. return;
  229. }
  230. }
  231. int MapInstruction(UINT_PTR original_addr, UINT_PTR new_addr, PWORD hook_len, PWORD original_len)
  232. {
  233. UINT_PTR flag=0;
  234. int len=0;
  235. BYTE *src,*dst;
  236. src=(BYTE*)original_addr;
  237. dst=(BYTE*)new_addr;
  238. while((src-(BYTE*)original_addr)<5)
  239. {
  240. len=disasm(src);
  241. if (len==0) return -1;
  242. memcpy(dst,src,len);
  243. if ((dst[0]>>1)==0x74) //E8,E9
  244. {
  245. LARGE_INTEGER ptr;
  246. ptr.QuadPart=(UINT_PTR)src;
  247. INT_PTR temp=*(int*)(src+1);
  248. ptr.QuadPart+=temp+5;
  249. //UINT_PTR point_addr=((UINT_PTR)src)>>32;
  250. //temp=(UINT_PTR)src+5+temp;
  251. //point_addr=(point_addr<<32)|temp;
  252. dst[1]=0x15|((dst[0]&1)<<5);
  253. dst[0]=0xFF;
  254. *(DWORD*)(dst+2)=new_addr+0x18-(UINT_PTR)dst;
  255. *(UINT_PTR*)(new_addr+0x1E)=ptr.QuadPart;
  256. dst+=6;
  257. }
  258. else if (dst[0]==0xFF)
  259. {
  260. if (dst[1]==0x15||dst[1]==0x25)
  261. {
  262. BYTE* rel=src+6+*(DWORD*)(src+2);
  263. *(DWORD*)(dst+2)=new_addr+0x18-(UINT_PTR)dst;
  264. *(UINT_PTR*)(new_addr+0x1E)=*(UINT_PTR*)rel;
  265. dst+=6;
  266. }
  267. else dst+=len;
  268. }
  269. else dst+=len;
  270. src+=len;
  271. }
  272. if (hook_len) *hook_len=((UINT_PTR)dst-new_addr)&0xFF;
  273. if (original_len) *original_len=((UINT_PTR)src-original_addr)&0xFF;
  274. return 0;
  275. }
  276. int MapDataAndSplit(BYTE* current, const HookParam& hp)
  277. {
  278. BYTE* original=current;
  279. int data=hp.off; //Resolve data
  280. int split=hp.split;
  281. int flag=0;
  282. if (split==-0x40)
  283. {
  284. flag=1;
  285. if (data==-0x48)
  286. {
  287. *(DWORD*)(current)=0xCCC1874D; //xchg r8,r9
  288. return 3;
  289. }
  290. else
  291. {
  292. *(DWORD*)(current)=0x00C88B4D; // mov r9,r8
  293. current+=3;
  294. }
  295. }
  296. if (data>0)
  297. {
  298. *(DWORD*)current=0xE4848B4C;
  299. *(DWORD*)(current+0x4)=data+0x48; //mov r8, [rsp+$]
  300. current+=8;
  301. }
  302. else
  303. {
  304. data=-data;
  305. if (data==0x20) //esp, special case
  306. {
  307. *(DWORD*)current=0x49C48B4C; //mov r8,rsp
  308. *(DWORD*)(current+0x4)=0x48C083; //add r8,0x40;
  309. current+=7;
  310. }
  311. else
  312. {
  313. if (data!=0x40)
  314. {
  315. data>>=3;
  316. current[0]=0x4C|(data>>3);
  317. current[1]=0x8B;
  318. current[2]=0xC0|(data&7); //mov r8,$
  319. current+=3;
  320. }
  321. }
  322. }
  323. if (flag==0&&(hp.type&USING_SPLIT))
  324. {
  325. data=hp.split; //resolve split
  326. if (data>0)
  327. {
  328. *(DWORD*)current=0xE48C8B4C;
  329. *(DWORD*)(current+4)=data+0x48; //mov r9,[rsp+$]
  330. }
  331. else
  332. {
  333. data=-data;
  334. if (data==0x20) //esp, special case
  335. {
  336. *(DWORD*)current=0x49CC8B4C; //mov r9,rsp
  337. *(DWORD*)(current+0x4)=0x48C183; //add r9,0x40;
  338. current+=7;
  339. }
  340. else
  341. {
  342. if (data!=0x48)
  343. {
  344. data>>=3;
  345. current[0]=0x4C|(data>>3);
  346. current[1]=0x8B;
  347. current[2]=0xC8|data&7;
  348. current+=3;
  349. }
  350. }
  351. }
  352. }
  353. return current-original;
  354. }
  355. int TextHook::InsertHook()
  356. {
  357. NtWaitForSingleObject(hmMutex,0,0);
  358. int k=InsertHookCode();
  359. IthReleaseMutex(hmMutex);
  360. if (hp.type&HOOK_ADDITIONAL)
  361. {
  362. NotifyHookInsert();
  363. OutputConsole(hook_name);
  364. RegisterHookName(hook_name,hp.addr);
  365. }
  366. return k;
  367. }
  368. int TextHook::InsertHookCode()
  369. {
  370. //__debugbreak();
  371. if (hp.module&&(hp.type&MODULE_OFFSET)) //Map hook offset to real address.
  372. {
  373. UINT_PTR base=GetModuleBase(hp.module);
  374. if (base)
  375. {
  376. if (hp.function&&(hp.type&(FUNCTION_OFFSET)))
  377. {
  378. base=GetExportAddress(base,hp.function);
  379. if (base)
  380. hp.addr+=base;
  381. else
  382. {
  383. OutputConsole(L"Function not found in the export table.");
  384. current_hook--;
  385. return 1;
  386. }
  387. }
  388. else
  389. hp.addr+=base;
  390. hp.type&=~(MODULE_OFFSET|FUNCTION_OFFSET);
  391. }
  392. else
  393. {
  394. OutputConsole(L"Module not present.");
  395. current_hook--;
  396. return 1;
  397. }
  398. }
  399. TextHook* it;
  400. int i;
  401. for (i=0,it=hookman;i<current_hook;it++) //Check if there is a collision.
  402. {
  403. if (it->Address()) i++;
  404. //it=hookman+i;
  405. if (it==this) continue;
  406. if (it->Address()<=hp.addr && it->Address()+it->Length()>hp.addr)
  407. {
  408. it->ClearHook();
  409. break;
  410. }
  411. }
  412. //Verify hp.addr.
  413. MEMORY_BASIC_INFORMATION info;
  414. NtQueryVirtualMemory(NtCurrentProcess(),(LPVOID)hp.addr,MemoryBasicInformation,&info,sizeof(info),0);
  415. if (info.Type&PAGE_NOACCESS) return 1;
  416. //Initialize common routine.
  417. UINT_PTR buffer=relay->RegisterSection((UINT_PTR)hp.addr);
  418. UINT_PTR inst=hp.addr;
  419. BYTE jmp_code[8], *ptr;
  420. while (*(UINT_PTR*)buffer) buffer+=0x10;
  421. jmp_code[0]=0xE8;
  422. *(DWORD*)(jmp_code+1)=(buffer-5-inst)&0xFFFFFFFF; //Hook address relative near jump.
  423. //memcpy(recover,common_hook,0x60); //Copy hook entry code.
  424. ptr=recover;
  425. memcpy(ptr,common_prologue,PROLOGUE_LENGTH);
  426. ptr+=PROLOGUE_LENGTH;
  427. ptr+=MapDataAndSplit(ptr,hp);
  428. memcpy(ptr,common_route,ROUTE_LENGTH);
  429. union
  430. {
  431. sendfun sf;
  432. UINT_PTR fun;
  433. };
  434. sf=&TextHook::Send;
  435. *(UINT_PTR*)(ptr+0xD+HOOK_DEBUG_HEAD)=fun; //Resolve high level function.
  436. *(UINT_PTR*)(ptr+0x17+HOOK_DEBUG_HEAD)=(UINT_PTR)this; //Resolve this pointer.
  437. ptr+=ROUTE_LENGTH;
  438. memcpy(ptr,common_epilogue,EPILOGUE_LENGTH);
  439. ptr+=EPILOGUE_LENGTH;
  440. MapInstruction(inst,(UINT_PTR)ptr,&hp.hook_len,&hp.recover_len); //Map hook instruction.
  441. *(WORD*)(ptr+hp.hook_len+HOOK_DEBUG_HEAD)=0x25FF; //Long jmp back.
  442. *(DWORD*)(ptr+hp.hook_len+2+HOOK_DEBUG_HEAD)=0x72-(ptr-recover)-hp.hook_len;
  443. *(UINT_PTR*)(recover+0x78+HOOK_DEBUG_HEAD)=inst+hp.recover_len;
  444. //*(UINT_PTR*)(recover+hp.hook_len+0x58)=inst+hp.recover_len;
  445. *(WORD*)buffer=0x25FF; //Relay buffer long jmp.
  446. *(LPVOID*)(buffer+6)=recover;
  447. memcpy(original,(LPVOID)hp.addr,hp.recover_len);
  448. //Check if the new hook range conflict with existing ones. Clear older if conflict.
  449. for (i=0,it=hookman;i<current_hook;it++)
  450. {
  451. if (it->Address()) i++;
  452. if (it==this) continue;
  453. if (it->Address()>=hp.addr && it->Address()<hp.hook_len+hp.addr)
  454. {
  455. it->ClearHook();
  456. break;
  457. }
  458. }
  459. //Insert hook and flush instruction cache.
  460. static DWORD int3[4]={0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC};
  461. UINT_PTR t=0x100,old,len;
  462. NtProtectVirtualMemory(NtCurrentProcess(),(PVOID*)&inst,&t,PAGE_EXECUTE_READWRITE,&old);
  463. NtWriteVirtualMemory(NtCurrentProcess(),(BYTE*)hp.addr,jmp_code,5,&t);
  464. len=hp.recover_len-5;
  465. if (len) NtWriteVirtualMemory(NtCurrentProcess(),(BYTE*)hp.addr+5,int3,len,&t);
  466. NtProtectVirtualMemory(NtCurrentProcess(),(PVOID*)&inst,&t,old,&old);
  467. NtFlushInstructionCache(NtCurrentProcess(),(LPVOID)hp.addr,hp.recover_len);
  468. NtFlushInstructionCache(NtCurrentProcess(),(LPVOID)hookman,0x1000);
  469. NtFlushInstructionCache(NtCurrentProcess(),(LPVOID)(buffer&~0xFFF),0x1000);
  470. return 0;
  471. }
  472. int TextHook::InitHook(LPVOID addr, UINT_PTR data, UINT_PTR data_ind,
  473. UINT_PTR split_off, UINT_PTR split_ind, UINT_PTR type, UINT_PTR len_off)
  474. {
  475. NtWaitForSingleObject(hmMutex,0,0);
  476. hp.addr=(UINT_PTR)addr;
  477. hp.off=data;
  478. hp.ind=data_ind;
  479. hp.split=split_off;
  480. hp.split_ind=split_ind;
  481. hp.type=type;
  482. hp.hook_len=0;
  483. hp.module=0;
  484. hp.length_offset=len_off&0xFFFF;
  485. current_hook++;
  486. if (current_available>=this)
  487. for (current_available=this+1;current_available->Address();current_available++);
  488. IthReleaseMutex(hmMutex);
  489. return this-hookman;
  490. }
  491. int TextHook::InitHook(const HookParam& h, LPWSTR name, WORD set_flag)
  492. {
  493. NtWaitForSingleObject(hmMutex,0,0);
  494. hp=h;
  495. hp.type|=set_flag;
  496. if (name&&name!=hook_name)
  497. {
  498. if (hook_name) delete hook_name;
  499. name_length=wcslen(name)+1;
  500. hook_name=new WCHAR[name_length];
  501. wcscpy(hook_name,name);
  502. }
  503. current_hook++;
  504. current_available=this+1;
  505. while (current_available->Address()) current_available++;
  506. IthReleaseMutex(hmMutex);
  507. return 1;
  508. }
  509. int TextHook::RemoveHook()
  510. {
  511. if (hp.addr)
  512. {
  513. NtWaitForSingleObject(hmMutex,0,0);
  514. UINT_PTR old,l=hp.hook_len,len;
  515. LPVOID base=(LPVOID)hp.addr;
  516. NtProtectVirtualMemory(NtCurrentProcess(),&base,&l,PAGE_EXECUTE_READWRITE,&old);
  517. NtWriteVirtualMemory(NtCurrentProcess(),(LPVOID)hp.addr,original,hp.recover_len,&len);
  518. NtFlushInstructionCache(NtCurrentProcess(),(LPVOID)hp.addr,hp.recover_len);
  519. NtProtectVirtualMemory(NtCurrentProcess(),&base,&l,old,&old);
  520. hp.hook_len=0;
  521. IthReleaseMutex(hmMutex);
  522. return 1;
  523. }
  524. return 0;
  525. }
  526. int TextHook::ClearHook()
  527. {
  528. NtWaitForSingleObject(hmMutex,0,0);
  529. int k=RemoveHook();
  530. if (hook_name) {delete hook_name;hook_name=0;}
  531. memset(this,0,sizeof(TextHook));
  532. //if (current_available>this) current_available=this;
  533. current_hook--;
  534. IthReleaseMutex(hmMutex);
  535. return k;
  536. }
  537. int TextHook::ModifyHook(const HookParam& hp)
  538. {
  539. WCHAR name[0x40];
  540. wcscpy(name,hook_name);
  541. ClearHook();
  542. InitHook(hp,name);
  543. InsertHook();
  544. return 0;
  545. }
  546. int TextHook::RecoverHook()
  547. {
  548. if (hp.addr)
  549. {
  550. InsertHook();
  551. return 1;
  552. }
  553. return 0;
  554. }
  555. int TextHook::SetHookName(LPWSTR name)
  556. {
  557. name_length=wcslen(name)+1;
  558. hook_name=new WCHAR[name_length];
  559. wcscpy(hook_name,name);
  560. return 0;
  561. }
  562. int TextHook::GetLength(UINT_PTR base, UINT_PTR in)
  563. {
  564. if (base==0) return 0;
  565. __int64 len;
  566. switch (hp.length_offset)
  567. {
  568. default:
  569. len = *((__int64*)base+hp.length_offset);
  570. if (len>=0)
  571. {
  572. if (hp.type&USING_UNICODE) len<<=1;
  573. break;
  574. }
  575. case 0:
  576. if (hp.type&USING_UNICODE) len=wcslen((LPWSTR)in)<<1;
  577. else len=strlen((char*)in);
  578. break;
  579. case 1:
  580. if (hp.type&USING_UNICODE) len=2;
  581. else
  582. {
  583. if (hp.type&BIG_ENDIAN) in>>=8;
  584. len=LeadByteTable[in&0xFF]; //Slightly faster than IsDBCSLeadByte
  585. }
  586. break;
  587. case 2:
  588. case 3:
  589. case 4:
  590. len = *((__int64*)base-hp.length_offset-3);
  591. if (len>=0)
  592. {
  593. if (hp.type&USING_UNICODE) len<<=1;
  594. }
  595. else
  596. {
  597. if (hp.type&USING_UNICODE) len=wcslen((LPWSTR)in)<<1;
  598. else len=strlen((char*)in);
  599. }
  600. break;
  601. }
  602. return len;
  603. }
  604. static LPVOID fun_table[14];
  605. //#define DEFAULT_SPLIT
  606. #ifdef DEFAULT_SPLIT
  607. #define SPLIT_SWITCH USING_SPLIT
  608. #else
  609. #define SPLIT_SWITCH 0
  610. #endif
  611. LPWSTR HookNameInitTable[]={
  612. L"GetTextExtentPoint32A",
  613. L"GetGlyphOutlineA",
  614. L"ExtTextOutA",
  615. L"TextOutA",
  616. L"GetCharABCWidthsA",
  617. L"DrawTextA",
  618. L"DrawTextExA",
  619. L"GetTextExtentPoint32W",
  620. L"GetGlyphOutlineW",
  621. L"ExtTextOutW",
  622. L"TextOutW",
  623. L"GetCharABCWidthsW",
  624. L"DrawTextW",
  625. L"DrawTextExW"
  626. };
  627. void InitDefaultHook()
  628. {
  629. fun_table[0]=GetTextExtentPoint32A;
  630. fun_table[1]=GetGlyphOutlineA;
  631. fun_table[2]=ExtTextOutA;
  632. fun_table[3]=TextOutA;
  633. fun_table[4]=GetCharABCWidthsA;
  634. fun_table[5]=DrawTextA;
  635. fun_table[6]=DrawTextExA;
  636. fun_table[7]=GetTextExtentPoint32W;
  637. fun_table[8]=GetGlyphOutlineW;
  638. fun_table[9]=ExtTextOutW;
  639. fun_table[10]=TextOutW;
  640. fun_table[11]=GetCharABCWidthsW;
  641. fun_table[12]=DrawTextW;
  642. fun_table[13]=DrawTextExW;
  643. hookman[0].InitHook( fun_table[0], -0x10,0,-8,0,USING_STRING|SPLIT_SWITCH ,3);
  644. hookman[1].InitHook( fun_table[1], -0x10,0,-8,0,BIG_ENDIAN|SPLIT_SWITCH, 1);
  645. hookman[2].InitHook( fun_table[2], 0x30,0,-8,0,USING_STRING|SPLIT_SWITCH, 7);
  646. hookman[3].InitHook( fun_table[3], -0x48,0,-8,0,USING_STRING|SPLIT_SWITCH, 5);
  647. hookman[4].InitHook( fun_table[4], -0x10,0,-8,0,BIG_ENDIAN|SPLIT_SWITCH, 1);
  648. hookman[5].InitHook( fun_table[5], -0x10,0,-8,0,USING_STRING|SPLIT_SWITCH, 3);
  649. hookman[6].InitHook( fun_table[6], -0x10,0,-8,0,USING_STRING|SPLIT_SWITCH, 3);
  650. hookman[7].InitHook( fun_table[7], -0x10,0,-8,0,USING_UNICODE | USING_STRING|SPLIT_SWITCH, 3);
  651. hookman[8].InitHook( fun_table[8], -0x10,0,-8,0,USING_UNICODE|SPLIT_SWITCH, 1);
  652. hookman[9].InitHook( fun_table[9], 0x30,0,-8,0,USING_UNICODE | USING_STRING|SPLIT_SWITCH, 7);
  653. hookman[10].InitHook(fun_table[10], -0x48,0,-8,0,USING_UNICODE | USING_STRING|SPLIT_SWITCH, 5);
  654. hookman[11].InitHook(fun_table[11], -0x10,0,-8,0,USING_UNICODE|SPLIT_SWITCH, 1);
  655. hookman[12].InitHook(fun_table[12], -0x10,0,-8,0,USING_UNICODE | USING_STRING|SPLIT_SWITCH, 3);
  656. hookman[13].InitHook(fun_table[13], -0x10,0,-8,0,USING_UNICODE | USING_STRING|SPLIT_SWITCH, 3);
  657. for (int i=0;i<sizeof(HookNameInitTable)/sizeof(LPWSTR);i++)
  658. hookman[i].SetHookName(HookNameInitTable[i]);
  659. }