امتیاز موضوع:
  • 1 رأی - میانگین امتیازات: 5
  • 1
  • 2
  • 3
  • 4
  • 5
Inject All the Things
نویسنده پیام
nImaarek آفلاین
badtrip
****

ارسال‌ها: 140
موضوع‌ها: 60
تاریخ عضویت: مهر ۱۳۸۹

تشکرها : 307
( 311 تشکر در 105 ارسال )
ارسال: #1
Inject All the Things
سلام،

تزریق DLL یک تکنیکی است که توسط نرم افزار مشروع برای افزودن و گسترش قابلیت به برنامه های دیگر، اشکال زدایی یا مهندسی معکوس استفاده می شود، همچنین معمولا توسط نرم افزارهای مخرب در بسیاری از موارد استفاده می شود. این بدان معنی است که از دیدگاه امنیتی، ضروری است بدانیم چگونه تزریق DLL کار می کند.
اگر می خواهید نمونه هایی از تهدید با استفاده از تزریق DLL را ببینید، نگاهی به اینجا بیاندازید..

7 تکنیک مختلف تزریق DLL که برای هر دو 32 و 64 بیت کار میکند را در یک پروژه ویژوال استودیو (به زبان سی) موجود میباشد که برای دانلود آن میتوانید به این لینک سری بزنید:
کد:
https://github.com/fdiskyou/injectAllTheThings

[تصویر:  screen.png]


تزریق DLL اساسا روند وارد کردن یا تزریق کد به یک فرایند در حال اجرا است.

میتوان کد را به صورتهای هر فایل assembly ،shellcode ،PE و غیره به فرآیند تزریق کرد حالا چرا باید از DLL استفاده کرد؟
 چون DLL های مورد نیاز در زمان اجرا بارگذاری می شوند (مثل libs مشترک در یونیکس). در این پروژه تنها از DLL استفاده شده است.

همچنین در نظر داشته باشید که برای شروع بازی با حافظه فرایندهای دیگر نیاز به یک سطح دسترسی مناسب داریم، با این حال درباره فرایندهای محافظت شده و سطوح امتیاز (privilege levels) ویندوز صحبت نمی کنم این یک موضوع کاملا متفاوت است.

همانطور که قبلا اشاره شد از تکنیک تزریق DLL در راه های قانونی هم استفاده میشود. به عنوان مثال، آنتی ویروس ها از این تکنیک برای قرار دادن قلاب ها (hooks) در همه ی فرایندهای در حال اجرا در سیستم استفاده میکنند با این تکنیک آنتی ویروس ها هر پروسه را نظارت میکنند. همچنین اهداف مخربی هم وجود دارد. یک روش رایج که اغلب مورد استفاده قرار می گیرد تزریق به فرآیند "lsass" است تا هش های رمز عبور دریافت شود.

DLL ها از اولین نسخه ی ویندوز وجود داشتند و API های ویندوز داخل فایل های DLL هستند که مهمترین آنها Kernel32.dll (که شامل توابع برای مدیریت حافظه، فرآیندها و موضوعات است)، User32.dll (توابع رابط کاربر) و GDI32.dll (توابع برای طراحی گرافیک و نمایش متن) هستند و همچنین API های مختلفی برای پیاده سازی تکنیک تزریق DLL وجود دارد.
شکل زیر روند تزریق DLL را نمایش میدهد:

[تصویر:  diagram.png]
همانطور که میبینید تزریق DLL در چهار مرحله انجام میشود:

Attach to the target/remote process
Allocate memory within the target/remote process
Copy the DLL Path, or the DLL, into the target/remote process memory
Instruct the process to execute the DLL
تمام این مراحل با فراخوانی یک مجموعه خاص از توابع API انجام می شود. هر تکنیک نیاز به نصب خاصی دارد که هر تکنیک ضعف ها و مزیت های خاص خودش را دارد.
ما گزینه های متعددی برای اجرای DLL در یک پروسه داریم که شایع ترین آنها استفاده از توابع CreateRemoteThread و NtCreateThreadEx است. با این حال، امکان انتقال DLL به عنوان پارامتر به این توابع وجود ندارد ما باید یک آدرس حافظه داشته باشیم که نقطه شروع اجرای DLL را نگه دارد... برای این، میبایست ما تخصیص حافظه را انجام دهیم DLL را با تابع LoadLibrary را در حافظه بارگذاری کنیم.

روش های که در این تاپیک به بررسی آنها میپردازیم:
CreateRemoteThread
NtCreateThreadEx
QueueUserAPC
SetWindowsHookEx
RtlCreateUserThread
Code cave via SetThreadContext
Reflective DLL
تابع LoadLibrary():
همانطور که در MSDN گفته شد، تابع LoadLibrary() "ماژول مشخص شده را به فضای آدرس فرایند فراخوانی بار می کند. ماژول مشخص شده ممکن است ماژول های دیگر را بارگیری کند."
کد:
HMODULE WINAPI LoadLibrary(
 _In_ LPCTSTR lpFileName
);

پارامتر ورودی این تابع فقط نام فایل است و ممکن است بدانید که یک مسئله مهم در اینجا این است که تابع LoadLibrary مسیر و فایل DLL بارگذاری شده را در برنامه ثبت می کند به همین دلیل به راحتی میتوان DLL را شناسایی کرد، برای جلوگیری از شناسایی DLL هنوز تکنیکی پیدا نشده است و همچنین توجه داشته باشید که اگر DLL قبلا با LoadLibrary () بار شده باشد دوباره اجرا نخواهد شد.

Attach to the target/remote process:
برای شروع، ما نیاز به برقراری ارتباط با فرآیند که میخواهیم به آن DLL تزریق کنیم داریم و برای این منظور ما از تابع OpenProcess استفاده می کنیم.
کد:
HANDLE WINAPI OpenProcess(
 _In_ DWORD dwDesiredAccess,
 _In_ BOOL  bInheritHandle,
 _In_ DWORD dwProcessId
);

اگر مستندات را در MSDN بخوانید خواهید دید که ما باید یک مجموعه خاص از حقوق دسترسی را درخواست کنیم. لیست کامل دسترسی را می توان در اینجا یافت.

Allocate memory within the target/remote process:
برای اختصاص دادن حافظه برای مسیر DLL ما از تابع VirtualAllocEx استفاده می کنیم. همانطور که در MSDN گفته شده است تابع VirtualAllocEx وضعیت یک منطقه حافظه در فضای آدرس مجازی یک فرآیند را مشخص یا تغییر میدهد.
کد:
LPVOID WINAPI VirtualAllocEx(
 _In_     HANDLE hProcess,
 _In_opt_ LPVOID lpAddress,
 _In_     SIZE_T dwSize,
 _In_     DWORD  flAllocationType,
 _In_     DWORD  flProtect
);

اساسا، این کار را به این صورت انجام میدهند:
کد:
// calculate the number of bytes needed for the DLL's pathname
DWORD dwSize = (lstrlenW(pszLibFile) + 1) * sizeof(wchar_t);

// allocate space in the target/remote process for the pathname
LPVOID pszLibFileRemote = (PWSTR)VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);

اگر میخواهید فضای کامل DLL را اختصاص دهید:
کد:
hFile = CreateFileW(pszLibFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

dwSize, = GetFileSize(hFile, NULL);

PVOID pszLibFileRemote = (PWSTR)VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);

Copy the DLL Path, or the DLL, into the target/remote process' memory:
مسیر DLL یا کل DLL را به حافظه فرآیند کپی کنید..

حال با استفاده از تابع WriteProcessMemory، فقط کپی مسیر DLL یا کل DLL را در فرآیند مقصد قرار می دهیم.
کد:
BOOL WINAPI WriteProcessMemory(
 _In_  HANDLE  hProcess,
 _In_  LPVOID  lpBaseAddress,
 _In_  LPCVOID lpBuffer,
 _In_  SIZE_T  nSize,
 _Out_ SIZE_T  *lpNumberOfBytesWritten
);

یا یه چیزی شبیه به ...

کد:
DWORD n = WriteProcessMemory(hProcess, pszLibFileRemote, (PVOID)pszLibFile, dwSize, NULL);
 
Instruct the process to execute the DLL:

CreateRemoteThread():

می توانیم بگوییم که CreateRemoteThread یک تکنیک کلاسیک و محبوب تزریق DLL است. همچنین، به خوبی تایید شده است که شامل مراحل زیر است:



پروسه هدف را با OpenProcess باز کنید
آدرس LoadLibrary را با استفاده از GetProcAddress پیدا کنید
برای استفاده از حافظه ذخیره شده برای مسیر DLL در فضای آدرس فرآیند از VirtualAllocEx استفاده کنید
نوشتن مسیر DLL در حافظه قبلی با WriteProcessMemory
استفاده از CreateRemoteThread برای ایجاد یک Thread جدید و فراخوانی تابع LoadLibrary با مسیر DLL به عنوان پارامتر

اگر به تابع CreateRemoteThread در MSDN سری بزنید می توانید ببینید که ما نیاز به یک اشاره گر به عملکرد تعریف شده کاربردی (application-defined function) از نوع LPTHREAD_START_ROUTINE داریم که از طریق اجرای Thread بدست میاید و نشان دهنده آدرس اولیه Thread در فرایند است این به این معناست که برای اجرای DLL ما فقط باید فرآیند را برای انجام این کارها سوق دهیم. تمام مراحل اولیه ذکر شده در بالا را ببینید:

کد:
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, dwProcessId);

// Allocate space in the remote process for the pathname
LPVOID pszLibFileRemote = (PWSTR)VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);

// Copy the DLL's pathname to the remote process address space
DWORD n = WriteProcessMemory(hProcess, pszLibFileRemote, (PVOID)pszLibFile, dwSize, NULL);

// Get the real address of LoadLibraryW in Kernel32.dll
PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");

// Create a remote thread that calls LoadLibraryW(DLLPathname)
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, pszLibFileRemote, 0, NULL);

برای اطلاعات کاملتر فایل t_CreateRemoteThread.cpp را بخوانید.

NtCreateThreadEx:
گزینه دیگری استفاده از NtCreateThreadEx است که یک تابع "ntdll.dll" نامشخص (undocumented) است و ممکن است در آینده حذف شود یا تغییر کند. این تکنیک کمی پیچیده تر است.
کد:
struct NtCreateThreadExBuffer {
 ULONG Size;
 ULONG Unknown1;
 ULONG Unknown2;
 PULONG Unknown3;
 ULONG Unknown4;
 ULONG Unknown5;
 ULONG Unknown6;
 PULONG Unknown7;
 ULONG Unknown8;
};

توضیحات خوبی در مورد این تابع وجود دارد. پیاده سازی این روش بسیار شبیه به آنچه که ما برای CreateRemoteThread انجام دادیم.
کد:
PTHREAD_START_ROUTINE ntCreateThreadExAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtCreateThreadEx");

LPFUN_NtCreateThreadEx funNtCreateThreadEx = (LPFUN_NtCreateThreadEx)ntCreateThreadExAddr;

NTSTATUS status = funNtCreateThreadEx(
 &hRemoteThread,
 0x1FFFFF,
 NULL,
 hProcess,
 pfnThreadRtn,
 (LPVOID)pszLibFileRemote,
 FALSE,
 NULL,
 NULL,
 NULL,
 NULL
 );

برای اطلاعات بیشتر سورس کد مربوط به 't_NtCreateThreadEx.cpp' بخوانید.

QueueUserAPC:
یک جایگزین برای تکنیک های قبلی که یک Thread جدید در فرآیند هدف را ایجاد نمی کند استفاده از تابع QueueUserAPC است.
همانطور که در MSDN مستند شده است، این فراخوانی، یک شی تماس نامتقارن در مد کاربر (APC یا asynchronous procedure call) را به صف APC در Thread هدف اضافه می کند.
کد:
DWORD WINAPI QueueUserAPC(
 _In_ PAPCFUNC  pfnAPC,
 _In_ HANDLE    hThread,
 _In_ ULONG_PTR dwData
);

بنابراین اگر ما نمیخواهیم Thread خودمان را ایجاد کنیم میتوانیم از QueueUserAPC برای ربودن (hijack) یک Thread موجود در فرآیند هدف استفاده کنیم.
یعنی، فراخوانی این تابع یک فراخوانی روش نامتقارن در Thread مشخص شده را صف می کند.

ما می توانیم به جای LoadLibrary یک تابع برگشتی APC استفاده کنیم، پارامتر می تواند یک اشاره گر به نام فایل DLL باشد که ما می خواهیم آن را تزریق کنیم.
کد:
DWORD dwResult = QueueUserAPC((PAPCFUNC)pfnThreadRtn, hThread, (ULONG_PTR)pszLibFileRemote);

اگر شما این تکنیک را امتحان میکنید ممکن است متوجه این موضوع شوید که هیچ زمانبندی به دنبال صف APC نیست، به این معنی که صف فقط زمانی مورد بررسی قرار می گیرد که Thread قابل تشخیص باشد (thread becomes alertable).

به همین دلیل ما اساسا هر Thread را hijack می کنیم، کد زیر را ببینید:


کد:
BOOL bResult = Thread32First(hSnapshot, &threadEntry);
 while (bResult)
 {
   bResult = Thread32Next(hSnapshot, &threadEntry);
   if (bResult)
   {
     if (threadEntry.th32OwnerProcessID == dwProcessId)
     {
       threadId = threadEntry.th32ThreadID;

       wprintf(TEXT("[+] Using thread: %i\n"), threadId);
       HANDLE hThread = OpenThread(THREAD_SET_CONTEXT, FALSE, threadId);
       if (hThread == NULL)
         wprintf(TEXT("[-] Error: Can't open thread. Continuing to try other threads...\n"));
       else
       {
         DWORD dwResult = QueueUserAPC((PAPCFUNC)pfnThreadRtn, hThread, (ULONG_PTR)pszLibFileRemote);
         if (!dwResult)
           wprintf(TEXT("[-] Error: Couldn't call QueueUserAPC on thread> Continuing to try othrt threads...\n"));
         else
           wprintf(TEXT("[+] Success: DLL injected via CreateRemoteThread().\n"));
         CloseHandle(hThread);
       }
     }
   }
 }

به عنوان یک مطالعه جانبی خوب است که بدانید این تکنیک توسط DOUBLEPULSAR استفاده شده است.
برای اطلاعات بیشتر سورس کد مربوط به 't_QueueUserAPC.cpp' بخوانید.

SetWindowsHookEx:
برای استفاده از این تکنیک میبایست درک کنیم که چگونه هوک ها در ویندوز کار می کنند در حقیقت هوک ها راهی برای رد کردن رویدادها هستند و به آنها عمل می کنند.

پست ادامه دارد....


فایل‌(های) پیوست شده بندانگشتی (ها)
       
۰۸-مرداد-۱۳۹۶, ۰۰:۴۶:۲۳
وب سایت ارسال‌ها
پاسخ
تشکر شده توسط : babyy, saeedsmk, lord_viper, Di Di, mirage0411


موضوعات مرتبط با این موضوع...
موضوع نویسنده پاسخ بازدید آخرین ارسال
Rolleyes یه برنامه میخوام فایل اجرایی رو به عکس inject کنه(خواهشا لازم دارم ضروریه) reza-ezdeham 11 7,410 ۰۵-فروردین-۱۳۹۰, ۱۲:۱۲:۴۸
آخرین ارسال: Ghoghnus

پرش به انجمن:


کاربرانِ درحال بازدید از این موضوع: 1 مهمان

صفحه‌ی تماس | IranVig | بازگشت به بالا | | بایگانی | پیوند سایتی RSS