{"id":292,"date":"2015-06-01T19:35:33","date_gmt":"2015-06-01T16:35:33","guid":{"rendered":"http:\/\/oguzkartal.net\/blog\/?p=292"},"modified":"2021-10-31T16:05:13","modified_gmt":"2021-10-31T13:05:13","slug":"api-hooking-yonlendirme-araya-girme-nedir-ve-nasil-yapilir","status":"publish","type":"post","link":"https:\/\/www.oguzkartal.net\/blog\/index.php\/2015\/06\/01\/api-hooking-yonlendirme-araya-girme-nedir-ve-nasil-yapilir\/","title":{"rendered":"API Hooking (Y\u00f6nlendirme, Araya Girme) Nedir ve Nas\u0131l Yap\u0131l\u0131r?"},"content":{"rendered":"<p>Merhaba<\/p>\n<p>Uzunca s\u00fcredir biraz detayl\u0131 bir yaz\u0131 yazmay\u0131 planl\u0131yordum. Takip edenler bilir Buffer Overflow konusunun 2. b\u00f6l\u00fcm\u00fcn\u00fc yazmay\u0131 planl\u0131yordum. Ancak k\u0131sa kesmemek ve olduk\u00e7a detayland\u0131rmak istedi\u011fimden ve bunun i\u00e7in de biraz fazlaca bo\u015f zaman olmas\u0131 gerekti\u011finden ikisini birbirine denk getirip konuyu i\u00e7ime sinecek \u015fekilde yazamam\u0131\u015ft\u0131m. Bu s\u00fcrede konuyu vakit bulduk\u00e7a haz\u0131rl\u0131yordum elbette. Ancak bir talihsizlik sonucu (Biraz benim de hata pay\u0131m var bu i\u015fte) Blog i\u00e7in yazd\u0131\u011f\u0131m i\u00e7erik verilerini (yaz\u0131, resim vs) talihsiz bir \u015fekilde kaybettim. Tabi o kadar detayland\u0131r\u0131p bitirmek \u00fczere oldu\u011fum i\u00e7eri\u011fin yok olmas\u0131 epeyce moralimi bozdu. O y\u00fczden uzunca bir s\u00fcre de bir\u015fey yazmaya i\u00e7im gitmedi. Ancak bu s\u00fcre zarf\u0131nda haz\u0131r bo\u015f vakit bulmu\u015fken API Hooking hakk\u0131nda \u015f\u00f6yle k\u0131saca bir\u015feyler karalamak istedim.<\/p>\n<p>Bu yaz\u0131n\u0131n konusu API Hooking. API nedir bunlar\u0131 anlatmaya gerek duymuyorum. Bu konuya mera\u011f\u0131n\u0131z varsa, ne oldu\u011funu zaten biliyorsunuzdur. O y\u00fczden bu yaz\u0131y\u0131 okuyan okuyucular\u0131n \u00f6nceden belli bir seviyede oldu\u011fu varsay\u0131m\u0131n\u0131 yap\u0131yorum. \u00c7\u00fcnk\u00fc konunun anla\u015f\u0131lmas\u0131 i\u00e7in bu \u015fart. Ancak yine de API ve API Hooking olay\u0131n\u0131n kavramsal olarak ne oldu\u011funu biliyor ama nedir&#8217;ini basit anlamda da \u00f6\u011frenmek istiyorsan\u0131z bu yaz\u0131da yine sizin i\u00e7in bir\u015feyler olacakt\u0131r. O y\u00fczden okuyabilirsiniz.<\/p>\n<p>Hooking terimini T\u00fcrk\u00e7e&#8217;ye tam olarak nas\u0131l \u00e7evirebilirim bilemiyorum. Kancalamak terimi biraz abes olabiliyor. O y\u00fczden ben &#8220;y\u00f6nlendirmek&#8221;, &#8220;araya girmek&#8221; \u015feklinde tan\u0131mlamak isterim.<\/p>\n<p>API Hooking yapman\u0131n birden fazla yolu mevcut. Bir\u00e7ok teknik, yakla\u015f\u0131m mevcut. \u00d6rne\u011fin e\u011fer ilgili API&#8217;ler bir tabloda tutuluyorsa bu tablo entry&#8217;lerini (girdi) replace etmek (de\u011fi\u015ftirmek). \u00d6rne\u011fin spesifik Kernel API&#8217;lar\u0131 i\u00e7in bu y\u00f6ntem kullan\u0131l\u0131r. Bu API&#8217;lar SSDT (System Service Descriptor Table) tutulur ve bu tablo girdilerini kendimizinkilerle de\u011fi\u015ftirdi\u011fimizde o API&#8217;lar\u0131 y\u00f6nlendirmi\u015f oluruz. Yahut IAT Hooking de benzer bir tekniktir. \u00c7al\u0131\u015ft\u0131r\u0131labilir dosyalar sistem servis API&#8217;lar\u0131n\u0131 kullanmak i\u00e7in kullan\u0131lan API ve Mod\u00fcl bilgilerini IAT (Import Address Table) ad\u0131 verilen tabloda tutar. Bunlar g\u00f6rece kolay y\u00f6ntemlerdir. Bir de dinamik kod y\u00fckleme, ta\u015f\u0131ma ve de\u011fi\u015ftirme tabanl\u0131 hooking y\u00f6ntemleri mevcuttur. \u00c7a\u011fr\u0131lan fonksiyon komutlar\u0131n\u0131 anl\u0131k olarak de\u011fi\u015ftirme, yahut relocation bu y\u00f6ntemlerden bir ka\u00e7\u0131d\u0131r.<\/p>\n<p>Anlataca\u011f\u0131m teknik konuyla tam dengede bilgi verebilmesi a\u00e7\u0131s\u0131ndan relocation (Yeniden konumland\u0131rma) tabanl\u0131 olacak.<\/p>\n<p>Relocation terimi kas\u0131t, \u00e7a\u011fr\u0131lan fonksiyonu \u00e7al\u0131\u015fan Process&#8217;in adres alan\u0131nda (Process Space) bir ba\u015fka noktaya ta\u015f\u0131yarak, orjinal lokasyonuna kendi fonksiyonumuzu yerle\u015ftirip araya girmeyi ifade eder.<\/p>\n<p>Kod da veri gibi bellek \u00fczerinde ard\u0131\u015f\u0131k bi\u00e7imde bulunur. Fig\u00fcr 1.&#8217;de \u00f6rnek bir yerle\u015fim g\u00f6r\u00fcn\u00fcyor.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/05\/2.png\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-294\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/05\/2.png\" alt=\"2\" width=\"740\" height=\"495\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/05\/2.png 986w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/05\/2-300x201.png 300w\" sizes=\"auto, (max-width: 740px) 100vw, 740px\" \/><\/a><\/p>\n<p><strong>Fig\u00fcr 1<\/strong><\/p>\n<p>\u00d6rnek olarak WriteFile Win32 API fonksiyonunu bellekteki yerle\u015fik d\u00fczenini g\u00f6r\u00fcyoruz. Ayn\u0131 \u015fekilde ilgili API fonksiyonuna \u00e7a\u011fr\u0131 yapan kodun yerle\u015fkesi de g\u00f6r\u00fcl\u00fcyor. Kodun nereye yerle\u015ftirilece\u011fi daha do\u011frusu nereye y\u00fcklenece\u011fi \u0130\u015fletim Sistemi&#8217;nin inyisatifindedir. Ve tasar\u0131m\u0131na g\u00f6re yerle\u015fke adresi de\u011fi\u015fkenlik g\u00f6sterebilir.<\/p>\n<p>Bizim bu b\u00f6lgeyi relocate (Yeniden konumland\u0131rma) etmemiz i\u00e7in orjinal fonksiyonun ba\u015flang\u0131\u00e7 adresini ve biti\u015f adresini bilmemiz gerek. Bu bilgileri kullanarak fonksiyonun ka\u00e7 byte uzunlu\u011funda oldu\u011funu da kolayl\u0131kla bilebiliriz.<\/p>\n<p>Kodun uzunlu\u011fu ve biti\u015f noktas\u0131n\u0131 neden bilmemiz gerek? Bilmeliyiz \u00e7\u00fcnk\u00fc esas kodu yeniden konumland\u0131rmak i\u00e7in ayr\u0131 bir bellek b\u00f6lgesine ihtiyac\u0131m\u0131z olacak. Orjinal kodu bizim kontrol\u00fcm\u00fczdeki bir bellek b\u00f6lgesine ta\u015f\u0131yaca\u011f\u0131z.<\/p>\n<h4><strong><span style=\"color: #ff0000;\">API Fonksiyonunun Adresi ve Uzunlu\u011funu Tespit Etmek<\/span><\/strong><\/h4>\n<p>Bu i\u015flem Hooking i\u015finin en temel ve \u00f6nemli k\u0131sm\u0131. \u00c7\u00fcnk\u00fc yanl\u0131\u015f yerden ve yanl\u0131\u015f uzunlukta kod ta\u015f\u0131nmas\u0131 demek uygulaman\u0131n an\u0131nda \u00e7\u00f6kmesine sebebiyet verecektir.<\/p>\n<p>API adresini bulmak zor de\u011fil. \u0130lgili mod\u00fcl\u00fc adres alan\u0131m\u0131za y\u00fckleyip prosed\u00fcr adresini bize veren <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ms684175%28v=vs.85%29.aspx\" target=\"_blank\" rel=\"noopener\">LoadLibrary<\/a> ve <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ms683212%28v=vs.85%29.aspx\" target=\"_blank\" rel=\"noopener\">GetProcAddress<\/a> Win32 API&#8217;lar\u0131 ile kolayca yapabiliriz.<\/p>\n<pre class=\"lang:c decode:true\">unsigned char *originalProc = NULL;\r\nHMODULE hlib = NULL; \r\nconst char *lib = \"kernel32.dll\";\r\nconst char *func = \"WriteFile\";\r\n\r\nhlib = LoadLibraryA(lib);\r\noriginalProc = (unsigned char *)GetProcAddress(hlib, func);<\/pre>\n<p>Yukar\u0131daki kod WriteFile fonksiyonuna ait mod\u00fcl\u00fc \u00f6nce y\u00fckleyip ard\u0131ndan, API fonksiyonunun adresini (Function Pointer) verecektir.<\/p>\n<p>Bu kolay k\u0131sm\u0131yd\u0131. Peki rutin ka\u00e7 byte uzunlu\u011funda ve nerede bitiyor?<br \/>\nBu k\u0131s\u0131m biraz u\u011fra\u015fmam\u0131z gereken k\u0131s\u0131m. \u00c7\u00fcnk\u00fc bunun tespiti i\u00e7in dinamik olarak kodlar\u0131 ba\u015flang\u0131\u00e7 adresinden itibaren analiz etmemiz gerekiyor. Yani disassemble ederek biti\u015f noktas\u0131n\u0131 bulabilmemiz laz\u0131m. x86 ve x64 assembly komutlar\u0131 de\u011fi\u015fken uzunlukta olduklar\u0131ndan komutlar\u0131 decode etmek (\u00e7\u00f6zmek) i\u00e7in bir \u00f6nceki komutun (instruction) ne oldu\u011funu anlayabilmek gerekir. \u00c7\u00fcnk\u00fc ayn\u0131 Opcode birden fazla anlama gelebilmektedir. Bunun ayr\u0131m\u0131 da ancak her bir komutun tam olarak \u00e7\u00f6z\u00fclebilmesiyle olur. Buna yaz\u0131n\u0131n ilerleyen k\u0131s\u0131mlar\u0131nda de\u011finece\u011fim \u00e7\u00fcnk\u00fc bu anlat\u0131mda yazd\u0131\u011f\u0131m kodlar k\u00fc\u00e7\u00fck \u00e7apta bu y\u00f6ntemi kullan\u0131yor olacaklar.<\/p>\n<p>Asl\u0131nda do\u011fru bir \u015fekilde komutlar\u0131 \u00e7\u00f6z\u00fcmlemek i\u00e7in Disassembler k\u00fct\u00fcphaneler kullan\u0131lmas\u0131 en do\u011frusudur. \u00c7\u00fcnk\u00fc ne kadar kendimiz disasm rutinleri yazsak da mutlaka eksik kalacakt\u0131r. Ben \u00f6rnek olmas\u0131 i\u00e7in disasm rutinlerini kendim yazd\u0131m. Konunun anla\u015f\u0131lmas\u0131 i\u00e7in. E\u011fer 3. parti disassemler k\u00fct\u00fcphaneleri isterseniz tavsiyem <a href=\"https:\/\/github.com\/gdabah\/distorm\" target=\"_blank\" rel=\"noopener\">Distrom<\/a> library&#8217;dir.<\/p>\n<p>\u015eimdi, bu i\u015fi bu yaz\u0131 i\u00e7in kendimiz yapaca\u011f\u0131z dedi\u011fime g\u00f6re ilk olarak yap\u0131lmas\u0131 gerekenden ba\u015flayal\u0131m. Bilmemiz gereken ilk \u015fey Win32 API fonksiyonlar\u0131n\u0131n STDCALL calling convention kullanmas\u0131d\u0131r. Bu bize fonksiyonunun sonunu tespit etmede bir ipucu verecek. stdcall bilindi\u011fi \u00fczere arg\u00fcman listesini sa\u011fdan sola aktar\u0131p, stack&#8217;i \u00e7a\u011fr\u0131lan fonksiyonun kendisinin d\u00fczenledi\u011fi bir yakla\u015f\u0131md\u0131r. Peki bu stack d\u00fczenleme nas\u0131l yap\u0131l\u0131r. \u00c7ok \u00e7ok \u00f6zel bir API olmad\u0131\u011f\u0131 m\u00fcddet\u00e7e stack ret x komutu ile d\u00fczenlenir. E\u011fer fonksiyon arg\u00fcman alm\u0131yorsa sadece ret ile geri d\u00f6n\u00fcl\u00fcr.<\/p>\n<p>ret ve ret x tam olarak ne yapar anlatmayaca\u011f\u0131m \u00e7\u00fcnk\u00fc en ba\u015fta da dedi\u011fim gibi bu yaz\u0131 i\u00e7in bunu zaten biliyor olman\u0131z gerek. \u0130lk i\u015f olarak fonksiyonun ba\u015flang\u0131\u00e7 noktas\u0131ndan itibaren ret veya ret x &#8216;e denk gelene kadar kod \u00fczerinde dola\u015fmak.<\/p>\n<p>&nbsp;<\/p>\n<p>A\u015fa\u011f\u0131da 32 bit WriteFile fonksiyonunun assembly kod d\u00f6k\u00fcm\u00fcn\u00fc g\u00f6r\u00fcyorsunuz.<\/p>\n<pre class=\"lang:asm decode:true\">_WriteFileImplementation@20:\r\n76C61282 8B FF                mov         edi,edi  \r\n76C61284 55                   push        ebp  \r\n76C61285 8B EC                mov         ebp,esp  \r\n76C61287 8B 4D 14             mov         ecx,dword ptr [ebp+14h]  \r\n76C6128A 85 C9                test        ecx,ecx  \r\n76C6128C 74 03                je          _WriteFileImplementation@20+0Fh (76C61291h)  \r\n76C6128E 83 21 00             and         dword ptr [ecx],0  \r\n76C61291 8B 45 08             mov         eax,dword ptr [ebp+8]  \r\n76C61294 83 F8 F4             cmp         eax,0FFFFFFF4h  \r\n76C61297 0F 84 C2 DF 02 00    je          _WriteFileImplementation@20+2DFDDh (76C8F25Fh)  \r\n76C6129D 83 F8 F5             cmp         eax,0FFFFFFF5h  \r\n76C612A0 0F 84 A5 DF 02 00    je          _WriteFileImplementation@20+2DFC9h (76C8F24Bh)  \r\n76C612A6 83 F8 F6             cmp         eax,0FFFFFFF6h  \r\n76C612A9 0F 84 88 DF 02 00    je          _WriteFileImplementation@20+2DFB5h (76C8F237h)  \r\n76C612AF FF 75 18             push        dword ptr [ebp+18h]  \r\n76C612B2 8B D0                mov         edx,eax  \r\n76C612B4 51                   push        ecx  \r\n76C612B5 FF 75 10             push        dword ptr [ebp+10h]  \r\n76C612B8 81 E2 03 00 00 10    and         edx,10000003h  \r\n76C612BE FF 75 0C             push        dword ptr [ebp+0Ch]  \r\n76C612C1 50                   push        eax  \r\n76C612C2 83 FA 03             cmp         edx,3  \r\n76C612C5 74 29                je          _WriteFileImplementation@20+6Eh (76C612F0h)  \r\n76C612C7 E8 F5 04 00 00       call        _WriteFile@20 (76C617C1h)  \r\n76C612CC 5D                   pop         ebp  \r\n76C612CD C2 14 00             ret         14h  \r\n76C612D0 90                   nop  \r\n76C612D1 90                   nop  \r\n76C612D2 90                   nop  \r\n76C612D3 90                   nop  \r\n76C612D4 90                   nop<\/pre>\n<p>ve 64 bit assembly d\u00f6k\u00fcm\u00fc<\/p>\n<pre class=\"lang:asm decode:true\">WriteFileImplementation:\r\n0000000077821F80 FF F3                push        rbx  \r\n0000000077821F82 48 83 EC 30          sub         rsp,30h  \r\n0000000077821F86 33 DB                xor         ebx,ebx  \r\n0000000077821F88 4D 85 C9             test        r9,r9  \r\n0000000077821F8B 74 03                je          WriteFileImplementation+10h (077821F90h)  \r\n0000000077821F8D 41 89 19             mov         dword ptr [r9],ebx  \r\n0000000077821F90 83 F9 F4             cmp         ecx,0FFFFFFF4h  \r\n0000000077821F93 0F 83 49 5D 01 00    jae         TlsGetValue+166F2h (077837CE2h)  \r\n0000000077821F99 48 8B C1             mov         rax,rcx  \r\n0000000077821F9C 25 03 00 00 10       and         eax,10000003h  \r\n0000000077821FA1 48 83 F8 03          cmp         rax,3  \r\n0000000077821FA5 74 6F                je          WriteFileImplementation+96h (077822016h)  \r\n0000000077821FA7 48 8B 44 24 60       mov         rax,qword ptr [rsp+60h]  \r\n0000000077821FAC 48 89 44 24 20       mov         qword ptr [rsp+20h],rax  \r\n0000000077821FB1 E8 0E FC FF FF       call        WriteFile (077821BC4h)  \r\n0000000077821FB6 48 83 C4 30          add         rsp,30h  \r\n0000000077821FBA 5B                   pop         rbx  \r\n0000000077821FBB C3                   ret  \r\n0000000077821FBC 90                   nop  \r\n0000000077821FBD 90                   nop<\/pre>\n<p>\u015euan her iki assembly d\u00f6k\u00fcm\u00fcn\u00fc \u00e7ok dikkatli incelemenize gerek yok. \u0130lk a\u015famada kodun ba\u015flang\u0131\u00e7 ve biti\u015f noktalar\u0131na dikkat etmeniz yeterli. Her iki kodda baz\u0131 platform farkl\u0131l\u0131klar\u0131 haricinde ayn\u0131lar.<\/p>\n<p>32 bit d\u00f6k\u00fcmde g\u00f6rd\u00fc\u011f\u00fcn\u00fcz \u00fczere rutin ret 14h ile sonlanmaktad\u0131r. Stack rutin sonunda 20 byte eklenerek d\u00fczenlenip \u00e7\u0131k\u0131l\u0131yor (Hex: 14 , Onluk D\u00fczen: 20 byte).<\/p>\n<p>WriteFile API prototip&#8217;ine bakt\u0131\u011f\u0131m\u0131zda<\/p>\n<pre class=\"lang:default decode:true\">BOOL WINAPI WriteFile(\r\n  _In_        HANDLE       hFile,\r\n  _In_        LPCVOID      lpBuffer,\r\n  _In_        DWORD        nNumberOfBytesToWrite,\r\n  _Out_opt_   LPDWORD      lpNumberOfBytesWritten,\r\n  _Inout_opt_ LPOVERLAPPED lpOverlapped\r\n);<\/pre>\n<p>32 bitte her bir arg\u00fcman 4 byte uzunlu\u011funda ve 5 adet arg\u00fcmana sahip. Yani 20 byte.<br \/>\n64 bitte do\u011frudan bir ret g\u00f6r\u00fcyoruz. Bunun sebebi x64 platformunda parametre aktar\u0131m\u0131n\u0131n stack yerine registerlar arac\u0131l\u0131\u011f\u0131 ile yap\u0131lmas\u0131d\u0131r. Yani fastcall calling convention. Bu konuda biraz daha bilgi almak isterseniz https:\/\/msdn.microsoft.com\/en-us\/library\/ms235286.aspx adresine g\u00f6z atabilirsiniz.<\/p>\n<p>Buradan \u00e7\u0131karaca\u011f\u0131m\u0131z sonu\u00e7 x86 veya x64 i\u00e7in ge\u00e7erli olmak \u00fczere, fonksiyon bitimini bu komutlar\u0131 tespit ederek sa\u011flayabilece\u011fimiz. Bunun i\u00e7in de her iki komutun opcode de\u011ferini bilmemiz gerek.<\/p>\n<p>RET komutunun opcode de\u011feri 0xc3,<br \/>\nRET X komutunun opcode de\u011feri 0xc2&#8217;dir<\/p>\n<p>RET tek bytel\u0131k bir komut iken,\u00a0 RET X bir X operand\u0131 ald\u0131\u011f\u0131ndan ve bu operand 16 bitlik bir relative de\u011fer oldu\u011fundan 3 byte uzunlu\u011funda bir komuttur.<\/p>\n<p>\u00d6ncelikle ba\u015flang\u0131\u00e7 adresini bildi\u011fimiz fonksiyon i\u00e7in bir d\u00f6ng\u00fc kurarak bu noktay\u0131 bulmaya \u00e7al\u0131\u015fal\u0131m.<\/p>\n<pre class=\"lang:default decode:true\">#define OC_RET 0xc3\r\n#define OC_RET_N 0xc2\r\n\r\nint routineCodeSize = 0;\r\nunsigned char *originalProc = NULL;\r\nunsigned char *codeBytePtr = NULL;\r\nunsigned char opCode;\r\nHMODULE hlib = NULL;\r\nint maxCodeLength = 1024;\r\n\r\nhlib = LoadLibraryA(lib);\r\n\r\noriginalProc = (unsigned char *)GetProcAddress(hlib, func);\r\n\r\ncodeBytePtr = originalProc;\r\n\r\nwhile (routineCodeSize == 0)\r\n{\r\n\tif (maxCodeLength-- &lt;= 0)\r\n\t\treturn NULL;\r\n\r\n\tswitch (*codeBytePtr)\r\n\t{\r\n\t\tcase OC_RET:\r\n\t\t{\r\n\t\t\topCode = *(codeBytePtr + 1);\r\n\r\n\t\t\t\/\/bak bakalim gercekten rutin sonunda miyiz?\r\n\t\t\tif (opCode == 0x90 || opCode == 0xcc || opCode == 0x00)\r\n\t\t\t{\r\n\t\t\t\troutineCodeSize = ((codeBytePtr + 1) - originalProc);\r\n\r\n\t\t\t\tif (verbose)\r\n\t\t\t\t\txprintf(\"+ RET\\n\\n\");\r\n\t\t\t}\r\n\t\t}\r\n\t\tbreak;\r\n\t\tcase OC_RET_N:\r\n\t\t{\r\n\t\t\topCode = *(codeBytePtr + 2);\r\n\r\n\t\t\tif (opCode == 0x90 || opCode == 0xcc || opCode == 0x00)\r\n\t\t\t{\r\n\t\t\t\troutineCodeSize = ((codeBytePtr + 3) - originalProc); \/\/ret + 2 byte rel16 byte ret val\r\n\t\t\t\t\t\r\n\t\t\t\tif (verbose)\r\n\t\t\t\t\txprintf(\"+ RET X\\n\\n\");\r\n\t\t\t}\r\n\t\t}\r\n\t\tbreak;\r\n\t}\r\n\r\n\tcodeBytePtr++;\r\n}<\/pre>\n<p>Yukar\u0131daki kod par\u00e7as\u0131 ile adresini ald\u0131\u011f\u0131m\u0131z fonksiyon kodu \u00fczerinde dola\u015farak uygun bir ret instruction&#8217;\u0131 aramaktad\u0131r. Ancak k\u00fc\u00e7\u00fck bir ek i\u015flem yapmam\u0131z faydal\u0131. Fonksiyon g\u00f6vdesinde belli bir \u015farta ba\u011fl\u0131 olarak rutin sonuna gelmeden de bir RET kodu bulunabilir. Biz sonraki byte&#8217;\u0131 da kontrol ederek ger\u00e7ekten rutin sonuna gelip gelmedi\u011fimizi \u00f6\u011freniyoruz. Win32 API fonksiyonlar\u0131n\u0131n son k\u0131s\u0131mlar\u0131 bellek \u00fczerinde genelde NOP (0x90) ile doldurulmu\u015ftur. Yahut bu de\u011fer varsay\u0131lan bir junk byte\u00a0 (Genelde 0xcc) ile de doldurulmu\u015f olabir. Yahut zero fill (0x00) halde de bulunabilir. Sonraki byte&#8217;\u0131 bu veriler olup olmad\u0131\u011f\u0131n\u0131 kontrol etmemiz ger\u00e7ek anlamda rutin sonunda olup olmad\u0131\u011f\u0131m\u0131z konusunda bize ipucu verecek. Elbette bu \u00e7ok garanti bir durum de\u011fil ancak konu i\u00e7in yapt\u0131\u011f\u0131m \u00e7al\u0131\u015fma i\u00e7in \u015fuan yeterli. Ge\u00e7erli bir ret koduna denk geldi\u011fimizde ret instruction adresinden ba\u015flang\u0131\u00e7 adresini \u00e7\u0131kard\u0131\u011f\u0131m\u0131zda bize rutinin boyutunu verecektir. Tabi bu ret adresine art\u0131 olarak ret uzunlu\u011funu da ilave etmemiz gerek. Bu de\u011fer ret i\u00e7in 1 byte iken ret x i\u00e7in 3 byte&#8217;d\u0131r. \u00c7\u00fcnk\u00fc ret x komutu ret opcode&#8217;u ve 2 byte kadar da stack&#8217;i d\u00fczenleyen byte miktar\u0131 kadar yer demek.<\/p>\n<p>Bu bilgiyi ald\u0131ktan sonra bize fonksiyonun kontrol\u00fcm\u00fczdeki yeni yeri i\u00e7in bellek tahsisat\u0131 yapmak gerekecek.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/3.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-299\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/3.png\" alt=\"3\" width=\"680\" height=\"454\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/3.png 986w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/3-300x201.png 300w\" sizes=\"auto, (max-width: 680px) 100vw, 680px\" \/><\/a><\/p>\n<p>Gerekli belle\u011fi ise VirtualAlloc API&#8217;\u0131 ile yapabiliriz. VirtualAlloc kullanmam\u0131z\u0131n sebebi bize istedi\u011fimiz bellek b\u00f6lgesinden yahut ona en yak\u0131n bellek b\u00f6lgesinden bellek alan\u0131 ay\u0131rabilmemizdir.\u00a0 \u00c7\u00fcnk\u00fc ta\u015f\u0131nacak b\u00f6lge orjinal bellek b\u00f6lgesine olabildi\u011fince yak\u0131n tutmam\u0131z bizim i\u00e7in avantaj sa\u011flayacak. Ayr\u0131ca o bellek b\u00f6lgesi \u00fczerinde hangi haklar\u0131n (okuma, yazma, \u00e7al\u0131\u015ft\u0131rma) atanabilece\u011fini belirleyebilmemiz. Bunun i\u00e7in <span class=\"lang:c decode:true  crayon-inline \">PAGE_EXECUTE_READWRITE<\/span> sabitini kullan\u0131yoruz. Bu bize hem \u00e7al\u0131\u015ft\u0131r\u0131labilir hem de okuma yazma yap\u0131labilir bir bellek sa\u011flayacakt\u0131r.<\/p>\n<pre class=\"lang:c decode:true\">void *requiredFunctionAddress = originalProc - routineCodeSize - 1024;\r\nunsigned char *newFunc = NULL;\r\n\r\nwhile (newFunc == NULL)\r\n{\r\n\t\/\/nop alani icin ekstradan 32 byte bellek iste\r\n\tnewFunc = VirtualAlloc(requiredFunctionAddress, routineCodeSize + 32, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r\n\t\t\r\n\trequiredFunctionAddress = ((unsigned char *)requiredFunctionAddress) - 0x1000;\r\n\r\n}\r\n<\/pre>\n<p>Bu i\u015flem i\u00e7in yazd\u0131\u011f\u0131m kod par\u00e7as\u0131 yukar\u0131daki gibi. Bunu bir d\u00f6ng\u00fc i\u00e7inde yap\u0131yoruz \u00e7\u00fcnk\u00fc i\u015fletim sistemi ilk seferde istedi\u011fimiz bellek b\u00f6lgesinden bellek tahsisat\u0131n\u0131 uygun g\u00f6rmeyebilir. \u0130lk a\u015famada orjinal fonksiyondan en az 1024 + rutin kod boyutu kadar geride (D\u00fc\u015f\u00fck Bellek b\u00f6lgesi) alan istiyoruz. E\u011fer ba\u015far\u0131s\u0131z olursak her bir seferinde 1 page kadar (4 kb) eksiltip tekrar deniyoruz taki bize uygun bir bellek verilene kadar. Kodda g\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere ek olarak 32 byte daha alan istedik. Sebebi fonksiyonu g\u00fcvenli \u015fekilde yerle\u015ftirebilmek. NOP (No Operation) herhangi bir yan etkiye sahip olmad\u0131\u011f\u0131ndan olas\u0131 bir kar\u0131\u015f\u0131kl\u0131kta herhangi bir \u00e7\u00f6p veri bulundurmamak.<\/p>\n<p>Bellek b\u00f6lgesini ald\u0131ktan sonra yapmam\u0131z gereken orjinal b\u00f6lgeden ay\u0131rd\u0131\u011f\u0131m\u0131z bellek b\u00f6lgesine rutini ta\u015f\u0131mak ve orjinal b\u00f6lgesi NOP ile temizlemek.<\/p>\n<pre class=\"lang:c decode:true \">\/\/Yeni kod bellek bolgesini Nop ile dolduralim cop opcode kalmasin.\r\nmemset(newFunc, 0x90, routineCodeSize + 32);\r\n\t\r\n\/\/orjinal fonksiyon kodunu yeni alana tasiyoruz.\r\nmemcpy(newFunc, originalProc, routineCodeSize);\r\n\r\n\/\/orjinal kod bellek bolgesinin readonly modunu readwrite yapiyoruz.\r\nif (!VirtualProtect(originalProc, routineCodeSize, PAGE_EXECUTE_READWRITE, &amp;oldProtection))\r\n{\r\n\txprintf(\"original code page could not switch to r\/w mode\");\r\n\tVirtualFree(newFunc, routineCodeSize + 32, MEM_RELEASE);\r\n\r\n\treturn NULL;\r\n}\r\n\t\r\n\/\/orjinal bellek bolgesini nopluyoruz. guvenli olmasi icin\r\nmemset(originalProc, 0x90, routineCodeSize);\r\n<\/pre>\n<p>Yukar\u0131daki kod par\u00e7as\u0131 ay\u0131rd\u0131\u011f\u0131m\u0131z bellek b\u00f6lgesini NOP ile dolduruyor ard\u0131ndan orjinal fonksiyon kodlar\u0131n\u0131 bellek b\u00f6lgemize memcpy ile basit\u00e7e kopyal\u0131yoruz. Ard\u0131ndan orjinal bellek b\u00f6lgesini temizliyoruz. Dikkat edilmesi gereken nokta orjinal bellek b\u00f6lgesini VirtualProtect ile yaz\u0131labilir \u015fekilde ayarlamak. Normalde bu alanlar sadece okunabilir ve \u00e7al\u0131\u015ft\u0131r\u0131labilir durumdad\u0131r. Bu ayarlamay\u0131 yapmad\u0131\u011f\u0131m\u0131z taktirde i\u015fletim sistemi illegal bir i\u015flem yapt\u0131\u011f\u0131m\u0131z\u0131 anlayacak ve Access Violation exception&#8217;\u0131 f\u0131rlatacakt\u0131r. Daha sonra bu b\u00f6lge \u00fczerinde rahatl\u0131kla oynama yapabiliriz.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/4.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-301\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/4.png\" alt=\"4\" width=\"680\" height=\"454\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/4.png 986w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/4-300x201.png 300w\" sizes=\"auto, (max-width: 680px) 100vw, 680px\" \/><\/a><\/p>\n<p>Ta\u015f\u0131ma i\u015fleminden sonra belle\u011fin durumu.<\/p>\n<p>Bu i\u015flem ard\u0131ndan orjinal bellek b\u00f6lgesini bir z\u0131plama noktas\u0131 olarak kullanaca\u011f\u0131z. Normalde di\u011fer uygulamalar halen bu adresi orjinal fonksiyonun adresi olarak g\u00f6receklerinden yap\u0131lan \u00e7a\u011fr\u0131lar bu adrese d\u00fc\u015fecektir. Bizim de yapmam\u0131z gereken buraya bir z\u0131plama noktas\u0131 haz\u0131rlamak. Bu alan trambolin fonksiyon olarak adland\u0131r\u0131l\u0131r. Trambolin benzetmesi de bu noktay\u0131 z\u0131plama noktas\u0131 olarak kullanmam\u0131zdan ileri gelir. Bu b\u00f6lgesi trambolin noktas\u0131 haline getirmek i\u00e7in buradan ay\u0131rd\u0131\u011f\u0131m\u0131z yeni fonksiyon adresine z\u0131plama yapan kodu olu\u015fturup yazmam\u0131z gereklidir. A\u015fa\u011f\u0131daki kod par\u00e7as\u0131 ile bu i\u015flemi yap\u0131yoruz. \u00d6rnek hem 64 bit hem de 32 bit \u00fczerinde \u00e7al\u0131\u015facak \u015fekilde yapmak istedi\u011fimden iki durum i\u00e7in de ayr\u0131 \u015fekilde bir kod haz\u0131rlamam\u0131z gerek.<\/p>\n<pre class=\"lang:c decode:true\">\/\/64 bit ise hook fonksiyonumuzun yeri 64 bit araligina giren bir noktada\r\n\/\/olabilir. o yuzden 64 bit bir registera adresi alip oraya zipliyoruz\r\nif (is64bit)\r\n{\r\n\t\/\/64 bit trambolin fonksiyon cagrisi\r\n\r\n\t\/\/mov rax, 64BIT_FUNCTION_ADDRESS\r\n\t\/\/jmp rax\r\n\r\n\t*originalProc = (unsigned char)0x48;\r\n\t*(originalProc + 1) = (unsigned char)0xB8;\r\n\t*((long long int *)(originalProc + 2)) = (long long int)hookFunction;\r\n\r\n\t*((unsigned short *)(originalProc + 10)) = 0xe0ff;\r\n\r\n}\r\nelse\r\n{ \r\n\t\/\/32 bit tramboline cagri\r\n\t\/\/32 bit ise normal bir jump ile bolgeye ziplayabiliriz.\r\n\t\t\r\n\t\/\/JMP NEW_RELATIVE_OFFSET\r\n\r\n\tint jmpOffset = ((unsigned char *)originalProc) - hookFunction;\r\n\r\n\tjmpOffset = -jmpOffset;\r\n\tjmpOffset -= 5; \/\/our jmp instruction size\r\n\r\n\t*originalProc = (unsigned char)0xE9;\r\n\r\n\t*((int *)(originalProc + 1)) = jmpOffset;\r\n}\r\n\r\nVirtualProtect(originalProc, routineCodeSize, oldProtection, &amp;oldProtection);<\/pre>\n<p>Kod aktif olarak \u00e7al\u0131\u015fan process&#8217;in 64 bit olup olmad\u0131\u011f\u0131na g\u00f6re devam ediyor. Bu kod par\u00e7as\u0131n\u0131 merak ediyorsan\u0131z github sayfamdaki gist kod par\u00e7as\u0131n\u0131 inceleyebilirsiniz.<\/p>\n<p><a href=\"https:\/\/gist.github.com\/0ffffffffh\/24438233cb99e33dde7b\">https:\/\/gist.github.com\/0ffffffffh\/24438233cb99e33dde7b<\/a><\/p>\n<p>64 bit i\u00e7in do\u011frudan bir 64 bit mutlak adrese jump yerine yeni fonksiyon adresini 64 bitlik bir register&#8217;a yaz\u0131p daha sonra o register&#8217;a z\u0131playan kod ile yapaca\u011f\u0131z. \u00c7\u00fcnk\u00fc bu adres 64 bit uzunlu\u011funda olabilir ve do\u011frudan 64 bit z\u0131plama yapmam\u0131z olas\u0131 de\u011fil. Bunun yerine ayn\u0131 i\u015fi g\u00f6recek \u015f\u00f6yle bir varvasyon kullanaca\u011f\u0131z.<\/p>\n<p>bu kod da<\/p>\n<p>MOV RAX, 64BIT_ADRES<br \/>\nJMP RAX<\/p>\n<p>\u015feklinde yap\u0131labilir. RAX, 32 bitlik EAX register&#8217;\u0131n\u0131n 64 bitlik kar\u015f\u0131l\u0131\u011f\u0131d\u0131r. Kalan k\u0131s\u0131mlar ise bildi\u011fimiz x86 komutlar\u0131 ile ayn\u0131<\/p>\n<p>MOV RAX, ADRES<\/p>\n<p>komutunun opcode kar\u015f\u0131l\u0131\u011f\u0131 0x48 ve 0xB8 de\u011ferleridir. Asl\u0131nda MOV komutunun opcode de\u011ferlerinden bir tanesi 0xB8&#8217;dir. ve MOV reg32, imm32 anlam\u0131na gelir. Yani 32 bitlik bir register&#8217;a 32 bit uzunlu\u011funda bir de\u011fer atanacak. Normalde 32 bit i\u00e7indir. Ancak ba\u015f\u0131ndaki 0x48 de\u011feri 64 bit platformda bir prefix de\u011feridir. (0x40 REX, 0x8 W bit) Buna REX prefix ad\u0131 verilir ve yap\u0131lacak i\u015flemin long mode yani 64 bit kar\u015f\u0131l\u0131\u011f\u0131 \u015feklinde yap\u0131lmas\u0131n\u0131 s\u00f6yler.<\/p>\n<p>REX prefix&#8217;i ile ilgili biraz daha fazla bilgi almak i\u00e7in<\/p>\n<p>http:\/\/wiki.osdev.org\/X86-64_Instruction_Encoding#REX_prefix<\/p>\n<p>adresinden faydalanabilirsiniz.\u00a0 Rex prefix&#8217;den sonra MOV opcode&#8217;u. Ard\u0131ndan da 64 bit yani 8 byte uzunlu\u011fundaki adresi orjinal fonksiyon ba\u015flang\u0131\u00e7 noktas\u0131ndaki adrese yazd\u0131k. Ard\u0131ndan jmp rax komutu i\u00e7in gerekli opcode&#8217;u adres+10 byte \u00f6tesine yaz\u0131yoruz. Bunun sebebi bir \u00f6nceki komutun toplamda 10 byte uzunlu\u011funda olmas\u0131 8 byte adres 2 byte da rex prefixli mov komutu.<\/p>\n<p>JMP RAX i\u00e7in opcode 0xff 0xe0<\/p>\n<p>S\u00f6z konusu i\u015flem e\u011fer 32 bit ise bunun i\u00e7in de standart bir relative offset&#8217;li bir JMP instruction&#8217;\u0131 yeterli olacakt\u0131r. Bu relative offset de\u011ferini bulabilmek i\u00e7in bulundu\u011fumuz bellek adresinden hook fonksiyonumuzun adresini ve art\u0131 5 byte kadar \u00e7\u0131kard\u0131\u011f\u0131m\u0131zda bu ofset de\u011ferini elde edebiliriz. 5 byte kadar daha \u00f6telememizin sebebi bu de\u011fere JMP komutunun uzunlu\u011funun da dahil edilmesi gereklili\u011fi JMP + REL32 komut uzunlu\u011fumuz 5 byte kadard\u0131r. Offset de\u011ferini de bulundu\u011fu noktadan &#8211; (negatif) operat\u00f6r\u00fc ile tersine \u00e7eviriyoruz \u00e7\u00fcnk\u00fc bu de\u011fer bulundu\u011fumuz adrese eklenerek hesaplanmaktad\u0131r.<\/p>\n<p>Bu offset de\u011ferini hesaplad\u0131ktan sonra JMP (0xE9) opcode ve ard\u0131ndan offset de\u011ferini adres \u00fczerine yazarak i\u015fin trambolin fonksiyon k\u0131sm\u0131n\u0131 halletmi\u015f oluyoruz.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/6.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-303\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/6.png\" alt=\"6\" width=\"927\" height=\"659\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/6.png 927w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/6-300x213.png 300w\" sizes=\"auto, (max-width: 927px) 100vw, 927px\" \/><\/a><\/p>\n<p>Bu i\u015flemden bellek g\u00f6r\u00fcn\u00fcm\u00fc yukar\u0131daki fig\u00fcr gibi olacakt\u0131r. Orjinal alan\u0131 z\u0131mplama noktas\u0131 olarak kulland\u0131k. Bu z\u0131pnan nokta da g\u00f6r\u00fcld\u00fc\u011f\u00fc gibi bizim Hook fonksiyonumuzun bellekteki yerle\u015fkesi.<\/p>\n<h4><span style=\"color: #ff0000;\"><strong>Hook Fonksiyonu<\/strong><\/span><\/h4>\n<p>Hook fonksiyonu orjinal API \u00e7a\u011fr\u0131s\u0131n\u0131n y\u00f6nlendirilece\u011fi ve yap\u0131lan \u00e7a\u011fr\u0131n\u0131n kontrol\u00fcm\u00fcze girece\u011fi, onu istedi\u011fimiz gibi filtreleyip, de\u011fi\u015ftirebilece\u011fimiz bir sahte API implementasyonudur. Yukar\u0131daki fig\u00fcrde trambolin noktas\u0131n\u0131n bu hook fonksiyonumuza i\u015faret etti\u011fi g\u00f6r\u00fclebilir. Hook edilmi\u015f bir API \u00e7a\u011fr\u0131ld\u0131\u011f\u0131nda \u00e7a\u011fr\u0131lar \u015fu s\u0131rada yap\u0131l\u0131yor olacak<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/7.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-305\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/7.png\" alt=\"7\" width=\"1072\" height=\"659\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/7.png 1072w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/7-300x184.png 300w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/7-1024x629.png 1024w\" sizes=\"auto, (max-width: 1072px) 100vw, 1072px\" \/><\/a><\/p>\n<p>1. ad\u0131mda her\u015feyden habersiz kod WriteFile API fonksiyonunu \u00e7a\u011f\u0131rmak istiyor. O orjinal fonksiyonun bulundu\u011fu adresi do\u011fru nokta varsayarak \u00e7a\u011fr\u0131y\u0131 oraya yap\u0131yor.<\/p>\n<p>2. ad\u0131mda trambolin noktas\u0131na ula\u015f\u0131yoruz. Herhangi bir \u015feyi de\u011fi\u015ftirmeden do\u011fruca Hook fonksiyonumuza z\u0131pl\u0131yoruz. Burada farkl\u0131 \u015feylerle oynay\u0131p \u00f6nemli register ve flag de\u011ferlerinin de\u011fi\u015fimine sebep olmamam\u0131z gerekiyor. E\u011fer b\u00f6yle bir \u015feye ihtiya\u00e7 duyacaksak dahi bu i\u015f i\u00e7in gerekli rutinleri yaz\u0131p bellek b\u00f6lgesine y\u00fcklememiz gereklidir.<\/p>\n<p>3. ad\u0131mda hook fonksiyonumuza giriyoruz. Bu ad\u0131mda gelen parametreleri iste\u011fimize g\u00f6re oynay\u0131p elimizde tuttu\u011fumuz bizim kontrol\u00fcm\u00fczdeki esas i\u015fi yapan fonksiyonu \u00e7a\u011f\u0131r\u0131yoruz ve d\u00f6n\u00fcyoruz.<\/p>\n<p>Bu 3 ad\u0131mdan olu\u015fan i\u015flem sonunda ilgili API ba\u015far\u0131l\u0131 \u015fekilde hook edilmi\u015f olacak.<\/p>\n<p>Peki hook fonksiyonumuz nerede ve nas\u0131l y\u00fcklendi?<\/p>\n<p>Hook fonksiyonumuzu hook kodumuzun i\u00e7ine C dili kullanarak yazm\u0131\u015f olmam\u0131z gerek. Bu sebepten ilgili hook fonksiyonu ne \u015fekilde hedef process&#8217;e enjekte edersek o \u015fekilde i\u015fletim sistemi taraf\u0131ndan zaten otomatik olarak haf\u0131zaya yerle\u015ftirilmi\u015f olacakt\u0131r. Bu noktadan sonra zaten bu hook fonksiyonun nerede oldu\u011funu bulmak \u00e7ocuk oyunca\u011f\u0131. A\u015fa\u011f\u0131da WriteFile \u00f6rne\u011fimiz i\u00e7in bir hook fonksiyon implementasyonu g\u00f6r\u00fcl\u00fcyor.<\/p>\n<pre class=\"lang:c decode:true\">typedef BOOL (WINAPI *WriteFilePtr)(\r\n\tHANDLE hFile,\r\n\tLPCVOID lpBuffer,\r\n\tDWORD nNumberOfBytesToWrite,\r\n\tLPDWORD lpNumberOfBytesWritten,\r\n\tLPOVERLAPPED lpOverlapped\r\n);\r\n\r\n\r\n#define allocMem(size, type) ((type *)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))\r\n\r\n#define allocStructMem(type) allocMem(sizeof(type),type)\r\n\r\n#define freeMem(ptr) HeapFree(GetProcessHeap(),0,ptr)\r\n\r\nWriteFilePtr originalWriteFile = NULL;\r\n\r\nBOOL WINAPI hooked_WriteFile(\r\n\tHANDLE hFile,\r\n\tLPCVOID lpBuffer,\r\n\tDWORD nNumberOfBytesToWrite,\r\n\tLPDWORD lpNumberOfBytesWritten,\r\n\tLPOVERLAPPED lpOverlapped\r\n\t)\r\n{\r\n\tBOOL result;\r\n\tconst char *hookMsg = \"HOOKED DATA: \";\r\n\tchar *manipData = allocMem(nNumberOfBytesToWrite + 64, char);\r\n\tint hookMsgLen = strlen(hookMsg);\r\n\r\n\txprintf(\"WriteFile cagrildi! -&gt; (%s)\\n\", lpBuffer);\r\n\r\n\tstrcpy(manipData, hookMsg);\r\n\tstrcat(manipData, (const char *)lpBuffer);\r\n\r\n\t\r\n\tresult = originalWriteFile(hFile, manipData, nNumberOfBytesToWrite + hookMsgLen, lpNumberOfBytesWritten, lpOverlapped);\r\n\r\n\r\n\tif (result)\r\n\t{\r\n\t\t\/\/kendi datamizi yazilan data uzunlugundan cikaralim\r\n\t\t*lpNumberOfBytesWritten -= hookMsgLen;\r\n\r\n\t\txprintf(\"%d byte yazildi\", *lpNumberOfBytesWritten);\r\n\t}\r\n\telse\r\n\t\txprintf(\"WriteFile basarisiz.\");\r\n\r\n\tfreeMem(manipData);\r\n\r\n\treturn result;\r\n}<\/pre>\n<p>Yukar\u0131daki hook fonksiyonu aynen WriteFile prototipine sahip olacak \u015fekilde kendimiz i\u00e7in yeniden yaz\u0131ld\u0131. Yap\u0131lan \u00e7a\u011fr\u0131 trambolin noktas\u0131ndan sonra do\u011frudan bu noktaya y\u00f6nlenecektir. \u00d6rne\u011fimizde yaz\u0131lmak istenen verinin ba\u015f\u0131na hook etti\u011fimizi belirtmek i\u00e7in bir mesaj prepend (Ba\u015f\u0131na ekleme) yaparak orjinal API fonksiyonunu \u00e7a\u011f\u0131r\u0131yoruz. \u0130\u015fin bu k\u0131sm\u0131 tamamen sizin yapmak istedi\u011finiz \u015feyle orant\u0131l\u0131 olarak de\u011fi\u015febilir. \u0130stenirse orjinalden farkl\u0131 bir dosya veya ak\u0131\u015f \u00fczerine ikincil olarak da yaz\u0131labilir.<\/p>\n<h4><span style=\"color: #ff0000;\"><strong>Problem!<\/strong><\/span><\/h4>\n<p>Her\u015fey buraya kadar yolunda ancak kodu yeniden konumland\u0131r\u0131rken (relocate) atlamamam\u0131z gereken bir nokta mevcut. E\u011fer hat\u0131rlarsan\u0131z trambolin fonksiyonu olu\u015ftururken bir relative offset kavram\u0131ndan bahsettik. Bu ofset de\u011ferinin i\u015flemci taraf\u0131ndan o an \u00e7al\u0131\u015fan kodun adresi baz al\u0131narak hesapland\u0131\u011f\u0131n\u0131 s\u00f6ylemi\u015ftim.<\/p>\n<p>Peki ta\u015f\u0131d\u0131\u011f\u0131m\u0131z kod verisi i\u00e7inde de buna benzer relative offset de\u011ferlerine sahip komut serileri varsa ne olacak? Cevab\u0131 basit bu ofset de\u011ferleri eski fonksiyon yerle\u015fkesini baz al\u0131narak olu\u015fturuldu\u011fu i\u00e7in ta\u015f\u0131nan yeni yerinde ge\u00e7ersiz olacak ve API fonksiyon rutini bamba\u015fka noktalara y\u00f6nlenecek ya bekledi\u011fimizden \u00e7ok farkl\u0131 bir sonu\u00e7 alaca\u011f\u0131z ya da \u00e7ok b\u00fcy\u00fck ihtimalle process&#8217;in \u00e7\u00f6kt\u00fc\u011f\u00fcn\u00fc g\u00f6rece\u011fiz.<\/p>\n<p>\u00c7\u00f6z\u00fcm?<\/p>\n<p>Bu i\u015fin \u00e7\u00f6z\u00fcm\u00fc biraz me\u015fakkatli say\u0131labilir. \u00c7\u00fcnk\u00fc bu komutlar\u0131 tespit edip bunlar\u0131n da ofsetlerini yeniden hesaplatt\u0131rmam\u0131z \u015fart. Yaz\u0131m\u0131n ba\u015f\u0131nda bu i\u015fi ger\u00e7ek anlamda yapmak istiyorsak bir disassemler library kullanmam\u0131z\u0131n \u00e7ok yararl\u0131 olaca\u011f\u0131n\u0131 bu y\u00fczden belirtmi\u015ftim. Ancak ben \u00f6rne\u011fimiz i\u00e7in bunu manuel olarak kar\u015f\u0131la\u015fabilece\u011fimiz senaryolara uygun bi\u00e7imde bulup hesaplatt\u0131rmak istiyorum. Yapt\u0131\u011f\u0131m testlerde de bir\u00e7ok API fonksiyonunda gerek 32 bit gerek 64 bit problem \u00e7\u0131kmadan ba\u015far\u0131yla \u00e7al\u0131\u015ft\u0131\u011f\u0131n\u0131 s\u00f6yleyebilirim. Problem \u00e7\u0131kanlarda ise ufak d\u00fczenlemelerle bunlar\u0131n \u00f6n\u00fcne ge\u00e7mek \u00e7ok zor de\u011fil.<\/p>\n<p>\u00c7\u00f6z\u00fcmden \u00f6nce relative offset kullanabilen ve s\u0131k\u00e7a rutinlerde kullan\u0131lan komutlar neler olabilir bunlar\u0131 bilmek gerekli. Yukar\u0131daki WriteFile API assembly d\u00f6k\u00fcm\u00fcne tekrar \u00e7\u0131k\u0131p \u015f\u00f6yle bir bakarsak birka\u00e7 nokta g\u00f6z\u00fcm\u00fcze \u00e7arpacakt\u0131r. Ya da siz zahmet etmeyin ben WriteFile&#8217;\u0131n 64 bit assembly d\u00f6k\u00fcm\u00fcn\u00fc tekrar buraya ekleyeyim.<\/p>\n<pre class=\"lang:c decode:true \">WriteFileImplementation:\r\n0000000077821F80 FF F3                push        rbx  \r\n0000000077821F82 48 83 EC 30          sub         rsp,30h  \r\n0000000077821F86 33 DB                xor         ebx,ebx  \r\n0000000077821F88 4D 85 C9             test        r9,r9  \r\n0000000077821F8B 74 03                je          WriteFileImplementation+10h (077821F90h)  \r\n0000000077821F8D 41 89 19             mov         dword ptr [r9],ebx  \r\n0000000077821F90 83 F9 F4             cmp         ecx,0FFFFFFF4h  \r\n0000000077821F93 0F 83 49 5D 01 00    jae         TlsGetValue+166F2h (077837CE2h)  \r\n0000000077821F99 48 8B C1             mov         rax,rcx  \r\n0000000077821F9C 25 03 00 00 10       and         eax,10000003h  \r\n0000000077821FA1 48 83 F8 03          cmp         rax,3  \r\n0000000077821FA5 74 6F                je          WriteFileImplementation+96h (077822016h)  \r\n0000000077821FA7 48 8B 44 24 60       mov         rax,qword ptr [rsp+60h]  \r\n0000000077821FAC 48 89 44 24 20       mov         qword ptr [rsp+20h],rax  \r\n0000000077821FB1 E8 0E FC FF FF       call        WriteFile (077821BC4h)  \r\n0000000077821FB6 48 83 C4 30          add         rsp,30h  \r\n0000000077821FBA 5B                   pop         rbx  \r\n0000000077821FBB C3                   ret  \r\n0000000077821FBC 90                   nop  \r\n0000000077821FBD 90                   nop<\/pre>\n<p>Yukar\u0131daki d\u00f6k\u00fcmden 6, 9, 13 ve 16. sat\u0131rlara dikkat vermenizi istiyorum. 3. adet \u015fartl\u0131 z\u0131plama (conditional jump) ve bir adet CALL rutin dallanma komutu g\u00f6rmekteyiz. Bu komutlar relative offset ile \u00e7al\u0131\u015fan komutlard\u0131r ve i\u015fte biz bu noktalar\u0131 yeniden hesaplamam\u0131z gerekli.<\/p>\n<p>Ancak dikkat! Her instruction farkl\u0131 bi\u00e7imlerde farkl\u0131 adres, operand tiplerine g\u00f6re \u00e7al\u0131\u015fabilir ve komut ad\u0131 ayn\u0131 olmas\u0131na ra\u011fmen Opcode de\u011ferleri farkl\u0131 olabilir. \u00d6rne\u011fin CALL komutunu ele al\u0131rsak,<\/p>\n<p>Bir instruction set referans sitesinden ald\u0131\u011f\u0131m CALL opcode de\u011ferleri.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/8.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-309\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/8.png\" alt=\"8\" width=\"784\" height=\"189\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/8.png 784w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/8-300x72.png 300w\" sizes=\"auto, (max-width: 784px) 100vw, 784px\" \/><\/a><\/p>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc gibi bir CALL komutunun 8 farkl\u0131 opcode&#8217;u var ve her biri i\u015flemci i\u00e7in farkl\u0131 bir anlam ta\u015f\u0131maktad\u0131r. Peki kendi durumumuza gelirsek relative yap\u0131lan CALL komutlar\u0131n\u0131 tespit etmemiz gerekti\u011fini biliyoruz. Yukar\u0131daki WriteFile d\u00f6k\u00fcm\u00fcne bakarsak 16. sat\u0131rda bu \u015fekilde bir CALL yap\u0131ld\u0131\u011f\u0131n\u0131 g\u00f6rebiliriz. Ve solundaki opcode d\u00f6k\u00fcm\u00fcne bakarsan\u0131z E8 ile ba\u015flad\u0131\u011f\u0131n\u0131 g\u00f6rebilirsiniz. Yani bir rel16\/32 instruction&#8217;\u0131 mevcut. Yine ayn\u0131 \u015fekilde \u015fartl\u0131 dallanma komutlar\u0131 i\u00e7in de bu aynen ge\u00e7erlidir.<\/p>\n<p>Bu opcode de\u011ferlerini ba\u015fta Intel ve AMD developer reference d\u00f6k\u00fcmanlar\u0131 ba\u015fta olmak \u00fczere bir\u00e7ok siteden k\u00fc\u00e7\u00fck bir aramayla bulabilirsiniz. Benim referans ald\u0131\u011f\u0131m site <a href=\"http:\/\/ref.x86asm.net\/coder64.html\">http:\/\/ref.x86asm.net\/coder64.html<\/a> bu adrestedir. Olduk\u00e7a detayl\u0131 ve i\u015fe yarar.<\/p>\n<p>Ben bana laz\u0131m olan de\u011ferleri olu\u015fturup hook kodumun i\u00e7erisine tan\u0131mlam\u0131\u015ft\u0131m.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/9.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-311\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/9.png\" alt=\"9\" width=\"475\" height=\"591\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/9.png 475w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/9-241x300.png 241w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/9-300x373.png 300w\" sizes=\"auto, (max-width: 475px) 100vw, 475px\" \/><\/a><\/p>\n<p>\u015euan i\u00e7in baz\u0131 anlams\u0131z gelebilecek tan\u0131mlamalar g\u00f6r\u00fcyor olabilirsiniz. Onlara ilerleyen k\u0131s\u0131mlarda de\u011finece\u011fim.<\/p>\n<p>\u0130lk de\u011finece\u011fim \u015fey CALL instruction&#8217;\u0131 hakk\u0131nda. Yukar\u0131daki tan\u0131mlara bak\u0131ld\u0131\u011f\u0131nda bir de CALL komutu i\u00e7in MOD RM \u015feklinde tan\u0131ml\u0131 bir de\u011fer g\u00f6r\u00fcyorsunuz. Mod rm ad\u0131 verilen durum ilgili komutun hangi adres modunda, hangi registerin yahut register yerine bir bellek b\u00f6lgesi mi kullan\u0131lacak onu belirtmek i\u00e7in kullan\u0131lan bir bitfield (bit alan\u0131, dizisi)dir. 0xff ile ba\u015flad\u0131\u011f\u0131nda bunlar dikkate al\u0131narak yorumlan\u0131r. Ve her bit aral\u0131\u011f\u0131n\u0131n bir anlam\u0131 mevcuttur. B\u00f6ylece gereksiz yere yeni adres modlar\u0131 i\u00e7in opcode ay\u0131rmak zorunda kal\u0131nmaz. Tek byte&#8217;l\u0131k bir de\u011fer ile hangi adres modunda, hangi registerlar veya bellek b\u00f6lgesi mi kullan\u0131lacak i\u015flemci anlar. Bizim \u015fuan bilmemiz gereken e\u011fer 0xFF mevcutsa sonraki byte&#8217;\u0131n kontrol edilerek esasen hangi komutun \u00e7al\u0131\u015ft\u0131r\u0131lmak istendi\u011fini bulmak istememizdir.<\/p>\n<p>Mod rm ile ilgili biraz daha bilgi almak isterseniz<\/p>\n<p><a href=\"http:\/\/www.c-jump.com\/CIS77\/CPU\/x86\/X77_0060_mod_reg_r_m_byte.htm\">http:\/\/www.c-jump.com\/CIS77\/CPU\/x86\/X77_0060_mod_reg_r_m_byte.htm<\/a> adresine u\u011frayabilirsiniz.<\/p>\n<p>Burada k\u00fc\u00e7\u00fck bir hat\u0131rlatma, e\u011fer komut tek operand alan bir komut ise MOD RM deki REG bit blo\u011funun bize \u00e7al\u0131\u015ft\u0131rlacak komut hakk\u0131nda bilgi sa\u011flamas\u0131. Intel developer manual&#8217;da bu konuya ili\u015fkin \u015f\u00f6yle yaz\u0131lm\u0131\u015ft\u0131r.<\/p>\n<p><em>If the instruction does not require a second operand, then the Reg\/Opcode field may be used as an opcode extension.<br \/>\n<\/em><br \/>\nCALL komutu da tek operandl\u0131 oldu\u011fundan bu k\u0131sm\u0131 di\u011fer tek operandl\u0131 komutlardan ay\u0131rmak i\u00e7in kullanabiliriz. Yukar\u0131da verdi\u011fim linke dikkat ederseniz REG blo\u011funun 3. ve 5. bitler aras\u0131 oldu\u011funu g\u00f6r\u00fcrs\u00fcn\u00fcz. Biz buradaki veriyi al\u0131p binary 11 , (Onluk d\u00fczende 7) ile and ledi\u011fimizde bize opcode t\u00fcr\u00fcn\u00fc verecektir. Peki neyin ne oldu\u011funu nereden bilece\u011fiz. Bunun i\u00e7in ba\u015fta referans olarak size verdi\u011fim kaynaktan yararland\u0131m.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/10.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-313\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/10.png\" alt=\"10\" width=\"329\" height=\"251\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/10.png 329w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/10-300x229.png 300w\" sizes=\"auto, (max-width: 329px) 100vw, 329px\" \/><\/a><\/p>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere hangi de\u011fer hangi komuta i\u015faret ediyor g\u00f6rebiliyoruz. Biraz yukar\u0131daki tan\u0131mlama b\u00f6l\u00fcm\u00fcnde de ayn\u0131 \u015fekilde sabitlerimi tan\u0131mlad\u0131m. E\u011fer 0xFF prefixi ile kar\u015f\u0131la\u015ft\u0131rsak sonraki byte&#8217;\u0131 (x &gt;&gt; 3) &amp; 7 i\u015fleminden ge\u00e7irip bize laz\u0131m olan bir instruction olup olmad\u0131\u011f\u0131n\u0131 tespit edece\u011fiz.<\/p>\n<p>Arama yapan d\u00f6ng\u00fcm\u00fcz i\u00e7ine a\u015fa\u011f\u0131daki kod par\u00e7as\u0131n\u0131 ekleyebiliriz.<\/p>\n<pre class=\"lang:c decode:true\">#define OC_CALL_REL\t\t\t0xe8\r\n#define OC_CALL_MODRM\t\t0xff\r\n#define OC_JCC_NEAR\t\t\t0x0f\r\n\r\n#define OC_JCC_BEGIN\t\t0x80\r\n#define OC_JCC_END\t\t\t0x8F\r\n\r\n#define OCX_CALL\t\t\t2\r\n#define OCX_CALLF\t\t\t3\r\n#define OCX_JMP\t\t\t\t4\r\n#define OCX_JMPF\t\t\t5\r\n\r\n\r\n\/*\r\n0 -&gt; INC\t\tR \/ M8 \/ M16 \/ M32\r\n1 -&gt; DEC\t\tR \/ M8 \/ M16 \/ M32\r\n2 -&gt; CALL\t\tR \/ m16 \/ m32\r\n3 -&gt; CALLF\t\tM16 : 16 \/ 32\r\n4 -&gt; JMP\t\tR \/ m16 \/ 32\r\n5 -&gt; JMPF\t\tM16 : 16 \/ 32\r\n6 -&gt; PUSH\t\tR \/ M16 \/ 32\r\n*\/\r\n\r\n#define getInstrByModrm(modRm) ((modRm &gt;&gt; 3)  &amp; 7)\r\n\r\nint isMov(unsigned char opCode) {\r\n\tif (opCode &gt;= 0x88 &amp;&amp; opCode &lt;= 0x8D)\r\n\t\treturn 1;\r\n\r\n\tif (opCode &gt;= 0xA0 &amp;&amp; opCode &lt;= 0xA3)\r\n\t\treturn 1;\r\n\r\n\tswitch (opCode)\r\n\t{\r\n\t\tcase 0xB0:\r\n\t\tcase 0xB8:\r\n\t\tcase 0xC6:\r\n\t\tcase 0xC7:\r\n\t\t\treturn 1;\r\n\t}\r\n\r\n\treturn 0;\r\n}\r\n\r\n\r\n\/\/+++++++++++++++++++++++++++++++\r\n\/\/+++++++++++++++++++++++++++++++\r\n\r\ncase OC_CALL_MODRM:\r\n{\r\n\t\/\/previous opcode is one of the MOV opcode?\r\n\t\/\/0xFF is EDI,EDI operand for MOV\r\n\tif (isMov(*(codeBytePtr - 1)))\r\n\t\tbreak;\r\n\r\n\tif (getInstrByModrm(*(codeBytePtr + 1)) == OCX_CALL)\r\n\t{\r\n\t\toff = *((int *)(codeBytePtr + 2));\r\n\t\taddReloc(hook,codeBytePtr + 2, off, 4);\r\n\r\n\t\tif (verbose)\r\n\t\t\txprintf(\"MODRM based CALL found at 0x%p -&gt; RELOFFSET: %x (%d)\\n\\n\", codeBytePtr, off,off);\r\n\r\n\t\t\/\/detect size\r\n\t}\r\n}\r\nbreak;<\/pre>\n<p>Kodda 0xff de\u011ferine denk geldi\u011fimizde sonraki byte&#8217;\u0131 anlatt\u0131\u011f\u0131m \u015fekilde kontrol ediyoruz ve e\u011fer bir CALL i\u015flemi ise onu relocation listemize dahil ediyoruz. Dikkatinizi \u00e7ekmi\u015f olabilir \u00f6ncesinde bir k\u00fc\u00e7\u00fck kontrol mevcut. Her 0xff prefix manas\u0131na gelmeyebilir. \u00d6rne\u011fin bir 0xff mov komutu i\u00e7in anlaml\u0131 bir de\u011ferdir. Yani<\/p>\n<p>MOV EDI,EDI komutunda mov operasyonunun edi register&#8217;\u0131ndan edi, register&#8217;\u0131na yap\u0131lmas\u0131n\u0131 s\u00f6yler.\u00a0 Bu komutlarla Win32 API fonksiyonlar\u0131n\u0131n ba\u015f\u0131nda kar\u015f\u0131la\u015fabiliriz. Bu komutun yapt\u0131\u011f\u0131 bir i\u015f yoktur sadece iki bytel\u0131k bir NOP g\u00f6revi g\u00f6r\u00fcr ve Microsoft taraf\u0131ndan geli\u015ftirilmi\u015f detours k\u00fct\u00fcphanesi i\u00e7in kullan\u0131labilecek bir hotpatch noktas\u0131 olarak i\u015flev g\u00f6r\u00fcr. Neyse.<\/p>\n<p>CALL k\u0131sm\u0131n\u0131 tamamlad\u0131ktan sonra s\u0131rada \u015fartl\u0131 dallanmalar mevcut. Bunlar\u0131n da ofsetlerini yeniden hesaplamam\u0131z gerekti\u011fini s\u00f6ylemi\u015ftik. \u015eartl\u0131 NEAR dallanmalar 2 byte uzunlu\u011funda (two byte opcode) komutlard\u0131r. Ve normal JCC dallanma opcode&#8217;u haricine ba\u015f\u0131na bir 0x0F de\u011feri al\u0131r. Daha sonraki byte ile de hangi t\u00fcr \u015fartl\u0131 dallanma komutu kullan\u0131lacaksa ona ait opcode bulunur. \u015eartl\u0131 dallanmalar\u0131n opcode de\u011fer aral\u0131\u011f\u0131<\/p>\n<p>0x80 ile 0x8F aral\u0131\u011f\u0131ndad\u0131r. Bu aral\u0131kta bir de\u011fere rastlarsak bir \u015fartl\u0131 dallanma \u00fczerindeyiz diyebiliriz.<\/p>\n<pre class=\"lang:c decode:true \">case OC_JCC_NEAR: \/\/two byte len\r\n{\r\n\t\/\/0x80 - 0x8F kosullu dallanma komutlari\r\n\r\n\topCode = *(codeBytePtr + 1);\r\n\r\n\tif (opCode &gt;= OC_JCC_BEGIN &amp;&amp; opCode &lt;= OC_JCC_END)\r\n\t{\r\n\t\toff = *((int *)(codeBytePtr + 1 + 1));\r\n\r\n\t\taddReloc(hook,codeBytePtr + 2, off, 4);\r\n\r\n\t\tif (verbose)\r\n\t\t\txprintf(\"REL_JCC found at 0x%p -&gt; RELOFFSET: %x (%d)\\n\\n\", codeBytePtr, off, off);\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\tcodeBytePtr += 6;\r\n\t}\r\n}\r\nbreak;<\/pre>\n<p>d\u00f6ng\u00fc i\u00e7ine dahil etmemiz gereken kod par\u00e7as\u0131 yukar\u0131daki gibi. Demin anlatt\u0131\u011f\u0131m olay\u0131n koda yans\u0131t\u0131lm\u0131\u015f hali. B\u00f6yle bir noktaya denk geldi\u011fimizde yine bunu relocation listemize al\u0131yoruz. Daha sonra bunlar\u0131 yeniden hesaplayaca\u011f\u0131z. addReloc fonksiyonu bu adres ve verileri bir linked list (Ba\u011fl\u0131 liste)&#8217;e ekleyen basit bir fonksiyon.<\/p>\n<pre class=\"lang:c decode:true \">typedef struct _relocBranchInfo\r\n{\r\n\tunsigned char *addr;\r\n\tint relOffset;\r\n\tint size;\r\n}relocBranchInfo;\r\n\r\ntypedef struct _relocBranchList\r\n{\r\n\tstruct _relocBranchList *head;\r\n\tstruct _relocBranchList *next;\r\n\trelocBranchInfo *rbi;\r\n}relocBranchList;\r\n\r\ntypedef struct _HOOKINFO\r\n{\r\n\trelocBranchList *relocList;\r\n\tvoid *originalApi;\r\n\tvoid *hookFunction;\r\n}HOOKINFO;\r\n\r\n\r\nvoid addReloc(HOOKINFO *hook, unsigned char *addr, int offset, int size)\r\n{\r\n\trelocBranchInfo *rbi = allocStructMem(relocBranchInfo);\r\n\trelocBranchList *node = allocStructMem(relocBranchList);\r\n\r\n\r\n\trbi-&gt;addr = addr;\r\n\trbi-&gt;relOffset = offset;\r\n\trbi-&gt;size = size;\r\n\r\n\tif (hook-&gt;relocList == NULL)\r\n\t{\r\n\t\thook-&gt;relocList = node;\r\n\t\tnode-&gt;head = node;\r\n\t\tnode-&gt;next = NULL;\r\n\t\tnode-&gt;rbi = rbi;\r\n\t}\r\n\telse\r\n\t{\r\n\t\thook-&gt;relocList-&gt;next = node;\r\n\t\tnode-&gt;head = hook-&gt;relocList-&gt;head;\r\n\t\tnode-&gt;next = NULL;\r\n\t\tnode-&gt;rbi = rbi;\r\n\r\n\t\thook-&gt;relocList = node;\r\n\t}\r\n}<\/pre>\n<p>\u0130\u015fi yapan kod basit bir linked list insert i\u015flemi yap\u0131yor. Oras\u0131 \u00e7ok \u00f6nemli de\u011fil. \u00d6nemli olan veri yap\u0131lar\u0131. En ba\u015fta tan\u0131ml\u0131 veri yap\u0131lar\u0131 instruction adresi, uzunlu\u011fu ve ofset de\u011ferini tutmaktad\u0131r. Bu bilgi bize laz\u0131m olacak.<\/p>\n<pre class=\"lang:c decode:true \">void recalculateAndPatch(unsigned char *origFuncBody, unsigned char *newFuncBody, relocBranchInfo *rbi)\r\n{\r\n\tBOOL isNewUpper = newFuncBody &gt; origFuncBody;\r\n\r\n\tint shiftSize;\r\n\tint newOffset;\r\n\r\n\tshiftSize = isNewUpper ? newFuncBody - origFuncBody : origFuncBody - newFuncBody;\r\n\r\n\tnewOffset = rbi-&gt;relOffset + shiftSize;\r\n\r\n\txprintf(\"Patch: %x -&gt; %x\\n\",rbi-&gt;relOffset, newOffset);\r\n\r\n\tint oldInstOffset= rbi-&gt;addr - origFuncBody;\r\n\r\n\t*((int *)(newFuncBody + oldInstOffset)) = newOffset;\r\n}\r\n<\/pre>\n<p>Yukar\u0131daki fonksiyon ofseti tekrar hesaplay\u0131p de\u011fi\u015ftirmektedir. Bu i\u015flemi de \u00f6nce orjinal fonksiyon ile yeni fonksiyon adresi aras\u0131ndaki uzakl\u0131\u011f\u0131 hesaplay\u0131p ofseti ne kadar kayd\u0131raca\u011f\u0131n\u0131 bulduktan sonra eski ofset de\u011feri \u00fczerine ekleyerek tamaml\u0131yor.<\/p>\n<p>\u0130kinci nokta ge\u00e7ersiz ofsete sahip komutun fonksiyon i\u00e7erisinde hangi ofsette bulundu\u011funu bilmek. Bunun i\u00e7in de komut adresinden orjinal fonksiyon adresini \u00e7\u0131kararak de\u011fi\u015ftirece\u011fimiz komutun ger\u00e7ekte hangi adreste oldu\u011funu bulaca\u011f\u0131z. Bu ofseti de hesaplad\u0131ktan sonra<\/p>\n<p>YENI_FONKSIYON_ADRESI + KOMUT_OFSETI = GERCEK_KOMUT_ADRESI<\/p>\n<p>e\u015fitli\u011fi ile de\u011fi\u015ftirece\u011fimiz adresi bularak yeni ofset de\u011ferini \u00fczerine yaz\u0131yoruz.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/11.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-315\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/11.png\" alt=\"11\" width=\"775\" height=\"871\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/11.png 775w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/11-267x300.png 267w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/11-300x337.png 300w\" sizes=\"auto, (max-width: 775px) 100vw, 775px\" \/><\/a><\/p>\n<p>Yukar\u0131daki komut ofsetleri \u00fczerine yeniden konumland\u0131rma yap\u0131lm\u0131\u015f ve yap\u0131lmam\u0131\u015f versiyonlar\u0131n\u0131 g\u00f6r\u00fcyorsunuz. Orjinal b\u0131rak\u0131lan fonksiyon g\u00f6vdesi ta\u015f\u0131nd\u0131ktan sonra yanl\u0131\u015f b\u00f6lgeye i\u015faret ederken, di\u011ferinde do\u011fru noktay\u0131 g\u00f6steriyor. Burada dikkat etmenizi istedi\u011fim k\u0131rm\u0131z\u0131 ve mavi d\u00f6rtgen i\u00e7ine al\u0131nm\u0131\u015f k\u0131s\u0131mlar.<\/p>\n<p>Mavi d\u00f6rtgen i\u00e7ine al\u0131nm\u0131\u015f komutlar relocation yap\u0131lmad\u0131\u011f\u0131 halde do\u011fru adres alan\u0131n\u0131 g\u00f6steriyorlar?<\/p>\n<p>Do\u011fru noktay\u0131 g\u00f6steriyorlar \u00e7\u00fcnk\u00fc orada yap\u0131lan \u015fartl\u0131 dallanma SHORT (k\u0131sa) dallanmad\u0131r ve -128 ve +128 aral\u0131\u011f\u0131ndaki k\u0131sa dallanmalar i\u00e7in ge\u00e7erlidir. Bu t\u00fcr dallanmalarda \u00e7ok b\u00fcy\u00fck ihtimalle fonksiyon g\u00f6vdesi i\u00e7inde yap\u0131lacak d\u00f6ng\u00fcsel dallanmalarda veya \u015fartl\u0131 durumlarda kullan\u0131laca\u011f\u0131 i\u00e7in onlar\u0131 yeniden konumland\u0131rmaya gerek duymad\u0131k. Yaz\u0131n\u0131n ba\u015flar\u0131nda bizi ilgilendiren k\u0131sm\u0131n NEAR JUMP komutlar\u0131 oldu\u011funu belirtmem bu y\u00fczdendi.<\/p>\n<h4><strong><span style=\"color: #ff0000;\">Sonu\u00e7<\/span><\/strong><\/h4>\n<p>Bunlar\u0131 bir araya do\u011fru bi\u00e7imde getirdi\u011fimizde ba\u015far\u0131l\u0131 bir API Hooking ger\u00e7ekle\u015ftirmi\u015f olaca\u011f\u0131z. Ben makaleyi haz\u0131rlarken \u00f6rnek olarak toparlay\u0131p \u00f6rnekte bahsi ge\u00e7en WriteFile fonksiyonunu hook edip manip\u00fcle ettim.<\/p>\n<p>\u00d6rnekte bir dosya a\u00e7al\u0131m ve o dosya \u00fczerine bir text verisi girelim. Hook fonksiyonu i\u00e7inden de bu veriye bizim istedi\u011fimiz bir veri ekleyip yazd\u0131ral\u0131m.<\/p>\n<pre class=\"font-size:16 lang:c decode:true\">HOOKINFO *writeFileHook=NULL;\r\n\r\nint main()\r\n{\r\n\tchar *test_data = \"BENI KIMSE TUTAMAZ!\";\r\n\tDWORD written = 0;\r\n\tHANDLE fileHandle;\r\n\r\n\twriteFileHook = hookAPIFunction(\"kernel32.dll\", \"WriteFile\", (unsigned char *)hooked_WriteFile);\r\n\r\n\tif (!writeFileHook)\r\n\t\treturn 0;\r\n\r\n\toriginalWriteFile = (WriteFilePtr)writeFileHook-&gt;originalApi;\r\n\r\n\tfileHandle = CreateFile(L\"D:\\\\TESTDOSYA.txt\", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, 0, NULL);\r\n\r\n\tWriteFile(fileHandle, test_data, strlen(test_data), &amp;written, NULL);\r\n\r\n\tCloseHandle(fileHandle);\r\n\t\r\n}\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Test kodumuz b\u00f6yle. \u00d6nce geli\u015ftirdi\u011fimiz hook sistemi ile WriteFile&#8217;\u0131 manip\u00fcle ediyoruz. Ard\u0131ndan olacaklara bakaca\u011f\u0131z.<\/p>\n<p>Program\u0131 \u00e7al\u0131\u015ft\u0131rd\u0131ktan sonra WriteFile fonksiyonun aras\u0131na ba\u015far\u0131yla girebildik.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/13.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-317\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/13.png\" alt=\"13\" width=\"677\" height=\"343\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/13.png 677w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/13-300x152.png 300w\" sizes=\"auto, (max-width: 677px) 100vw, 677px\" \/><\/a><\/p>\n<p>Ne yazd\u0131k, ne bulduk :)<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/14.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-318\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/14.png\" alt=\"14\" width=\"472\" height=\"280\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/14.png 472w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2015\/06\/14-300x178.png 300w\" sizes=\"auto, (max-width: 472px) 100vw, 472px\" \/><\/a><\/p>\n<h4><strong><span style=\"color: #ff0000;\">Son S\u00f6z<\/span><\/strong><\/h4>\n<p>API hooking derin ancak e\u011flenceli bir konu. Bu yaz\u0131da bu i\u015fin ne oldu\u011fu ve nas\u0131l yap\u0131ld\u0131\u011f\u0131 konusunu bir a\u00e7\u0131dan inceledik. Bir a\u00e7\u0131dan diyorum \u00e7\u00fcnk\u00fc en ba\u015fta bahsetti\u011fim gibi bu y\u00f6ntemlerden sadece bir tanesiydi. Ancak bu \u015fekliyle tam i\u015flevsel bir hooking&#8217;den bahsedemeyiz. Bunu i\u015flevsel hale getirmek i\u00e7in hedef programa nas\u0131l enjekte etmemiz gerekti\u011fi, nas\u0131l farkl\u0131 bir process&#8217;i kontrol alt\u0131na alabilece\u011fimiz konusu var ki o tamamen ba\u015fka bir konu. O y\u00fczden o konuyu da bunun devam\u0131 say\u0131lacak ayr\u0131 bir makalede vakit bulabilirsem de\u011finmek istiyorum.<\/p>\n<p>\u00c7al\u0131\u015fmada bahsi ge\u00e7en kodlar\u0131n tamam\u0131na <a href=\"https:\/\/github.com\/0ffffffffh\/Win32ApiHook\">https:\/\/github.com\/0ffffffffh\/Win32ApiHook<\/a> github repo sayfamdan ula\u015fabilirsiniz.<\/p>\n<p>Okudu\u011funuz i\u00e7in te\u015fekk\u00fcrler. Umuyorum faydal\u0131 olmu\u015ftur.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Merhaba Uzunca s\u00fcredir biraz detayl\u0131 bir yaz\u0131 yazmay\u0131 planl\u0131yordum. Takip edenler bilir Buffer Overflow konusunun 2. b\u00f6l\u00fcm\u00fcn\u00fc yazmay\u0131 planl\u0131yordum. Ancak k\u0131sa kesmemek ve olduk\u00e7a detayland\u0131rmak istedi\u011fimden ve bunun i\u00e7in de biraz fazlaca bo\u015f zaman olmas\u0131 gerekti\u011finden ikisini birbirine denk getirip konuyu i\u00e7ime sinecek \u015fekilde yazamam\u0131\u015ft\u0131m. Bu s\u00fcrede konuyu vakit bulduk\u00e7a haz\u0131rl\u0131yordum elbette. Ancak bir talihsizlik&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"twitterCardType":"","cardImageID":0,"cardImage":"","cardTitle":"","cardDesc":"","cardImageAlt":"","cardPlayer":"","cardPlayerWidth":0,"cardPlayerHeight":0,"cardPlayerStream":"","cardPlayerCodec":"","footnotes":""},"categories":[34,64,49,1],"tags":[33,53,81,77,80,46,79,78],"class_list":["post-292","post","type-post","status-publish","format-standard","hentry","category-oses","category-programming","category-security","category-uncategorized","tag-api","tag-assembly","tag-function","tag-hook","tag-tramboline","tag-windows","tag-x64","tag-x86"],"_links":{"self":[{"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/posts\/292","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=292"}],"version-history":[{"count":23,"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/posts\/292\/revisions"}],"predecessor-version":[{"id":919,"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/posts\/292\/revisions\/919"}],"wp:attachment":[{"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=292"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=292"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=292"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}