Programming/Win32 API2008. 12. 3. 11:36

CreateThread()는 쓰레드를 생성하는 함수이다.

이제 이것을 이용하여 Windows을 강제다운 시켜보겠다.(Win9x에서)

Win2k에서는 시스템이 느려지기는 하였으나, 다운되지는 않은 것 같다.


원리는 말그대로 자신의 스레드를 무한 생성해내고, 프로세스 자신의 우선순위를 높여서

시스템을 다운시키는 것이다.


코드는 이와 같다.


DWORD ThreadProc(PVOID pParameter)
{
        /*우선순위 변경*/

        SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
        while(1)
        {
                Sleep(1000);
        }
        return 0;
}


void main()
{
        DWORD dwThreadId=0;
LoopOfCreateThread:

        /*자기 자신의 우선순위를 증가시킨다.*/
        SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, NULL, NULL, &dwThreadId);
        __asm
        {
                cli                                        ;인터럽트 코드 클리어
                jmp LoopOfCreateThread         ;다시 스레드를 생성시키는 구간으로 점프.
        }
}

Posted by skensita
Programming/Win32 API2008. 12. 3. 11:11

이 프로그램은 제가 작성한 블루스크린을 띄우는 프로그램의 소스코드입니다.

실행 후, 아무 키나 누르면 다시 원상태로 되돌아옵니다.


#include <stdio.h>
#include <windows.h>
#include <wingdi.h>
#include <ddraw.h>
#define LINE(x)  (int)(14*(float)x)

BOOL IsDisplayed;
DWORD dwDelayTickCount;
char BChkText[64];
PVOID BChkCode;
PVOID BChkArg1;
PVOID BChkArg2;
PVOID BChkArg3;
PVOID BChkArg4;
char Driver[20];
PVOID RefAddress;
PVOID Base;
PVOID Date;

BOOL PrintVideoText(HWND hWnd, int x, int y, COLORREF BkColor, COLORREF TextColor, LPSTR FormatString, ...)
{
 LPSTR Text=(LPSTR)malloc(strlen(FormatString)*8);
 BOOL bStatus=FALSE;
 va_list args;
 HDC hDc;
 PAINTSTRUCT PaintStruct;
 hDc=BeginPaint(hWnd, &PaintStruct);
 SetBkColor(hDc, BkColor);
 SetTextColor(hDc, TextColor);
 va_start(args, FormatString);
 vsprintf(Text, FormatString, args);
 va_end(args);
 bStatus=TextOut(hDc, x, y, Text, strlen(Text));
 free((void *)Text);
 EndPaint(hWnd, &PaintStruct);
 ReleaseDC(hWnd, hDc);
 return bStatus;
}

void InitVideo(int x, int y)
{
 DEVMODE DevMode;
 ZeroMemory(&DevMode, sizeof(DevMode));
 DevMode.dmSize=sizeof(DevMode);
 DevMode.dmFields=DM_PELSWIDTH | DM_PELSHEIGHT;
 DevMode.dmPelsWidth=x;
 DevMode.dmPelsHeight=y;
 DevMode.dmColor=0;
 ChangeDisplaySettings(&DevMode, CDS_VIDEOPARAMETERS);
 ShowCursor(FALSE);
}

void UnInitVideo()
{
 DEVMODE DevMode;
 DevMode.dmSize=sizeof(DevMode);      
 DevMode.dmFields=DM_PELSWIDTH | DM_PELSHEIGHT;
 DevMode.dmPelsWidth=1024;
 DevMode.dmPelsHeight=768;
 DevMode.dmColor=1;
 ChangeDisplaySettings(&DevMode, 1);
 ShowCursor(TRUE);
}

BOOL TextOutEx(HDC hDc, int x, int y, LPSTR FormatString, ...)
{
 LPSTR Text=(LPSTR)malloc(strlen(FormatString)*8);
 BOOL bStatus=FALSE;
 va_list args;
 va_start(args, FormatString);
 vsprintf(Text, FormatString, args);
 va_end(args);
 bStatus=TextOut(hDc, x, y, Text, strlen(Text));
 free((void *)Text);
 return bStatus;
}

VOID DisplayBlueScreen(
 HWND hWnd,
 BOOL bKernelDumpPhysicalMemory,
 LPSTR BugCheckMessageText,
 PVOID KeBugCheckCode,
 PVOID BugCheckArgument1,
 PVOID BugCheckArgument2,
 PVOID BugCheckArgument3,
 PVOID BugCheckArgument4,
 LPSTR DriverName,
 PVOID ReferencedAddress,
 PVOID BaseAddress,
 PVOID DateStamp)
{
 HDC hDc;
 LOGFONT LogFont={NULL, };
 PAINTSTRUCT PaintStruct;
 HGDIOBJ FontObj, PrevFontObj;
 int y=0, DriverNameLength=0;
 if(DriverName) DriverNameLength=strlen(DriverName);
 hDc=BeginPaint(hWnd, &PaintStruct);
 /*RED=RGB(193, 54, 45)*/
 /*BLUE=RGB(0, 0, 132)*/
 SetBkColor(hDc, RGB(0, 0, 132));
 SetTextColor(hDc, RGB(255, 255, 255));
 LogFont.lfHeight=13;
 strcpy(LogFont.lfFaceName, TEXT("Lucida Console"));
 FontObj=(HGDIOBJ)CreateFontIndirect(&LogFont);
 PrevFontObj=SelectObject(hDc, FontObj);
 TextOutEx(hDc, 0, LINE(1), "A problem has been detected and Windows has been shut down to prevent damage");
 TextOutEx(hDc, 0, LINE(2), "to your computer.");
 if(DriverNameLength)
 {
  TextOutEx(hDc, 0, LINE(4), "The problem seems to be caused by the following file: %s", DriverName);
 }
 TextOutEx(hDc, 0, DriverNameLength ? LINE(6) : LINE(4), BugCheckMessageText);
 TextOutEx(hDc, 0, DriverNameLength ? LINE(8) : LINE(6), "If this is the first time you've seen this error screen,");
 TextOutEx(hDc, 0, DriverNameLength ? LINE(9) : LINE(7), "restart your computer. If this screen appears again, follow ");
 TextOutEx(hDc, 0, DriverNameLength ? LINE(10) : LINE(8), "these steps:");
 TextOutEx(hDc, 0, DriverNameLength ? LINE(12) : LINE(10), "Check to make sure any new hardware or software is properly installed.");
 TextOutEx(hDc, 0, DriverNameLength ? LINE(13) : LINE(11), "If this is a new installation, ask your hardware or software manufacturer");
 TextOutEx(hDc, 0, DriverNameLength ? LINE(14) : LINE(12), "for any windows updates you might need.");
 TextOutEx(hDc, 0, DriverNameLength ? LINE(16) : LINE(14), "If problems continue, disable or remove any newly installed hardware");
 TextOutEx(hDc, 0, DriverNameLength ? LINE(17) : LINE(15), "or software. Disable BIOS memory options such as caching or shadowing.");
 TextOutEx(hDc, 0, DriverNameLength ? LINE(18) : LINE(16), "If you need to use Safe Mode to remove or disable components, restart");
 TextOutEx(hDc, 0, DriverNameLength ? LINE(19) : LINE(17), "your computer, press F8 to select Advanced Startup Options, and then");
 TextOutEx(hDc, 0, DriverNameLength ? LINE(20) : LINE(18), "select Safe Mode.");
 TextOutEx(hDc, 0, DriverNameLength ? LINE(22) : LINE(20), "Technical information:");
 TextOutEx(hDc, 0, DriverNameLength ? LINE(24) : LINE(22), "*** STOP: 0x%p (0x%p, 0x%p, 0x%p, 0x%p)", KeBugCheckCode, BugCheckArgument1, BugCheckArgument2, BugCheckArgument3, BugCheckArgument4);
 if(DriverNameLength)
 {
  TextOutEx(hDc, 0, LINE(26), "***  %s - Address %p base at %p, Datestamp %p", DriverName, ReferencedAddress, BaseAddress, DateStamp);
 }
 if(KeBugCheckCode==(PVOID)0x50 || KeBugCheckCode==(PVOID)0x1E || KeBugCheckCode==(PVOID)0x24 ||
  KeBugCheckCode==(PVOID)0x58 || KeBugCheckCode==(PVOID)0x79)
 {
  //DO NOTHING
 }
 else
 {
  TextOutEx(hDc, 0, DriverNameLength ? LINE(28) : LINE(24), "Beginning dump of physical memory");
  if(bKernelDumpPhysicalMemory && (strncmp(BugCheckMessageText, "DRIVER_IRQL_NOT_LESS_OR_EQUAL", 29)==0 ||
   strncmp(BugCheckMessageText, "IRQL_NOT_LESS_OR_EQUAL", 22)==0))
  {
   int DumpProgress=1;
   TextOutEx(hDc, 0, DriverNameLength ? LINE(29) : LINE(25), "Dumping physical memory to disk: ");
   while(DumpProgress<=1000)
   {
    TextOutEx(hDc, 275, DriverName ? LINE(29) : LINE(25), "%.2d", DumpProgress/10);
    Sleep(10);
    DumpProgress+=1;
   }
  }
  TextOutEx(hDc, 0, DriverNameLength ? LINE(29) : LINE(25), "Physical memory dump complete.          ");
  TextOutEx(hDc, 0, DriverNameLength ? LINE(30) : LINE(26), "Contact your system administrator or technical support group for further");
  TextOutEx(hDc, 0, DriverNameLength ? LINE(31) : LINE(27), "assistance.");
 }
 DeleteObject(FontObj);
 SelectObject(hDc, PrevFontObj);
 EndPaint(hWnd, &PaintStruct);
}

int randEx()
{
 srand(GetTickCount() >> 4);
 return rand();
}

VOID RandomBugCheckParameter(
 OUT PCHAR BugCheckMessageText,
 OUT PVOID *KeBugCheckCode,
 OUT PVOID *BugCheckArgument1,
 OUT PVOID *BugCheckArgument2,
 OUT PVOID *BugCheckArgument3,
 OUT PVOID *BugCheckArgument4,
 OUT LPSTR DriverName,
 OUT PVOID *ReferencedAddress,
 OUT PVOID *BaseAddress,
 OUT PVOID *DateStamp)
{
 int BugCheckCodes[18]={0x0A, 0x1E, 0x24, 0x35, 0x3F, 0x50, 0x58, 0x76,
  0x79, 0x7F, 0xC5, 0xCE, 0xCF, 0xD0, 0xD1, 0xD4, 0xDE, 0xE2};
 char *BugCheckMessages[18]={"IRQL_NOT_LESS_OR_EQUAL", "KMODE_EXCEPTION_NOT_HANDLED",
  "NTFS_FILE_SYSTEM", "NO_MORE_IRP_STACK_LOCATIONS", "NO_MORE_SYSTEM_PTES",
  "PAGE_FAULT_IN_NONPAGED_AREA", "FTDISK_INTERNAL_ERROR", "PROCESS_HAS_LOCKED_PAGES",
  "MISMATCHED_HAL", "UNEXPECTED_KERNEL_MODE_TRAP", "DRIVER_CORRUPTED_EXPOOL",
  "DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS",
  "TERMINAL_SERVER_DRIVER_MADE_INCORRECT_MEMORY_REFERENCE",
  "DRIVER_CORRUPTED_MMPOOL", "DRIVER_IRQL_NOT_LESS_OR_EQUAL",
  "SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD",
  "POOL_CORRUPTION_IN_FILE_AREA", "MANUALLY_INITIATED_CRASH"};
 char *Drivers[25]={"Ndis.sys", "ipsec.sys", "Null.sys", "tcpip.sys",
  "wanarp.sys", "RSPSC.sys", "cdrom.sys", "ntoskrnl.exe", "ipfltdrv.sys",
  "acpi.sys", "netbios.sys", "atapi.sys", "USBSTOR.SYS", "vga.sys",
  "nv4.sys", "cdfs.sys", "isapnp.sys", "i8042prt.sys", "serial.sys",
  "modem.sys", "DISK.sys", "wstcodec.sys", "dxapi.sys", "ntoskrnl.exe",
  "win32k.sys"};
 ULONG BugCheckParameters[18][4]={
  {0xEA00ACFDL+randEx(), randEx()%2 ? 0xFF : 0x01, randEx()%2, 0xEA00ACFDL-randEx()},
  {randEx()%2 ? 0xC0000005 : 0x00000001, 0x80400000+randEx()*randEx(), 0x7FFFD174+randEx(), randEx()},
  {randEx()%1024, 0, 0xEBB0A538+randEx(), 0},
  {0xECAFEDFB+randEx(), 0, 0, 0},
  {0, 0, 0, 0},
  {0x80040000+randEx(), randEx()%2, 0x80000000+randEx()*randEx(), 0},
  {0, 0, 0, 0},
  {0, randEx()*randEx()*randEx(), randEx(), 0},
  {randEx()%3, randEx()%3, randEx()%3, 0},
  {0, 0, 0, 0},
  {0x80040000+randEx(), randEx()%2 ? 0xFF : 0x01, randEx()%2, 0x80000000+randEx()*randEx()},
  {0xEBACDAFE+randEx(), randEx()%2, 0xED000000+randEx()*randEx()*randEx(), 0},
  {0xEEADC013+randEx(), randEx()%2, 0xEF2DAA34+randEx()*randEx()-randEx(), 0},
  {0xE0000000+randEx()*randEx()+randEx(), randEx()%2 ? 0xFF : 0x01, randEx()%2, 0xEABCDEFA+randEx()},
  {0xDECABDDF+randEx()*2, randEx()%2 ? 0xFF : 0x01, randEx()%2, 0xDABCDEFA+randEx()},
  {0xDADECAFF+randEx()*randEx()+randEx(), randEx()%2 ? 0xFF : 0x01, randEx()%2, 0xDDDCDEFA+randEx()},
  {0, 0, 0, 0},
  {0, 0, 0, 0}
 };
 BOOL HasDriver[18]={1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0};
 ULONG ReferencedAddressList[18]={BugCheckParameters[0][3], BugCheckParameters[1][2],
  0, 0, 0, BugCheckParameters[5][2], 0, 0, 0, 0, BugCheckParameters[10][3],
  BugCheckParameters[11][2], BugCheckParameters[12][2], BugCheckParameters[13][3],
  BugCheckParameters[14][3], BugCheckParameters[15][3], 0, 0};
 int Index=randEx()%18;
 memset(BugCheckMessageText, NULL, sizeof(BugCheckMessageText));
 memset(DriverName, NULL, sizeof(DriverName));
 strcpy(BugCheckMessageText, BugCheckMessages[Index]);
 *KeBugCheckCode=(PVOID)BugCheckCodes[Index];
 *BugCheckArgument1=(PVOID)BugCheckParameters[Index][0];
 *BugCheckArgument2=(PVOID)BugCheckParameters[Index][1];
 *BugCheckArgument3=(PVOID)BugCheckParameters[Index][2];
 *BugCheckArgument4=(PVOID)BugCheckParameters[Index][3];
 if(HasDriver[Index]) strcpy(DriverName, Drivers[randEx()%25]);
 *ReferencedAddress=(PVOID)ReferencedAddressList[Index];
 *BaseAddress=(PVOID)(ReferencedAddressList[Index]-(randEx()*2)+(randEx()%2));
 *DateStamp=(PVOID)(randEx()*randEx()*abs(randEx()-randEx()));
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
 if(!IsDisplayed && iMessage==WM_PAINT)
 {
  RandomBugCheckParameter(BChkText, &BChkCode, &BChkArg1, &BChkArg2, &BChkArg3,
   &BChkArg4, Driver, &RefAddress, &Base, &Date);
 }
 switch(iMessage)
 {
  case WM_PAINT:
   DisplayBlueScreen(
    hWnd,
    IsDisplayed ? FALSE : TRUE,
    BChkText,
    BChkCode,
    BChkArg1,
    BChkArg2,
    BChkArg3,
    BChkArg4,
    Driver,
    RefAddress,
    Base,
    Date);
   IsDisplayed=TRUE;
   break;
  case WM_KEYDOWN:
   UnInitVideo();
   ShowCursor(TRUE);
   ExitProcess(0);
   break;
 }
 return DefWindowProc(hWnd, iMessage, wParam, lParam);
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
 HWND hWnd;
 MSG Msg;
 WNDCLASS WndClass;
 InitVideo(640, 480);
 WndClass.cbClsExtra=1;
 WndClass.cbWndExtra=0;
 WndClass.hbrBackground=(HBRUSH)CreateSolidBrush(RGB(0, 0, 132));//GetStockObject(13);
 WndClass.hCursor=(HCURSOR)LoadCursor(NULL, IDC_ARROW);
 WndClass.hIcon=LoadIcon(NULL, IDI_APPLICATION);
 WndClass.hInstance=hInstance;
 WndClass.lpfnWndProc=(WNDPROC)WndProc;
 WndClass.lpszClassName="DisplayBlueScreenClass32W";
 WndClass.lpszMenuName=NULL;
 WndClass.style=CS_HREDRAW | CS_VREDRAW;
 RegisterClass(&WndClass);
 hWnd=CreateWindow("DisplayBlueScreenClass32W", "DisplayBSOD", WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
       NULL, (HMENU)NULL, hInstance, NULL);
 SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
 ShowWindow(hWnd, SW_SHOW);
 while(GetMessage(&Msg, 0, 0, 0))
 {
  TranslateMessage(&Msg);
  DispatchMessage(&Msg);
 }
 UnInitVideo();
 return Msg.wParam;
}

아래는 실행 결과입니다.


사용자 삽입 이미지


※ 참고 : 이 블루스크린은 실제의 블루스크린(BSOD)와 차이가 날 수 있습니다.

Posted by skensita
Programming/Win32 API2008. 12. 3. 11:03

#include <stdio.h>
#include <conio.h>
#include <windows.h>

typedef long   NTSTATUS;

typedef enum _SYSTEM_INFORMATION_CLASS {
 SystemInformationClassMin=0,
 SystemBasicInformation=0,
 SystemProcessorInformation=1,
 SystemPerformanceInformation=2,
 SystemTimeOfDayInformation=3,
 SystemPathInformation=4,
 SystemNotImplemented1=4,
 SystemProcessInformation=5,
 SystemProcessesAndThreadsInformation=5,
 SystemCallCountInfoInformation=6,
 SystemCallCounts=6,
 SystemDeviceInformation=7,
 SystemConfigurationInformation=7,
 SystemProcessorPerformanceInformation=8,
 SystemProcessorTimes=8,
 SystemFlagsInformation=9,
 SystemGlobalFlag=9,
 SystemCallTimeInformation=10,
 SystemNotImplemented2=10,
 SystemModuleInformation=11,
 SystemLocksInformation=12,
 SystemLockInformation=12,
 SystemStackTraceInformation=13,
 SystemNotImplemented3=13,
 SystemPagedPoolInformation=14,
 SystemNotImplemented4=14,
 SystemNonPagedPoolInformation=15,
 SystemNotImplemented5=15,
 SystemHandleInformation=16,
 SystemObjectInformation=17,
 SystemPageFileInformation=18,
 SystemPagefileInformation=18,
 SystemVdmInstemulInformation=19,
 SystemInstructionEmulationCounts=19,
 SystemVdmBopInformation=20,
 SystemInvalidInfoClass1=20,
 SystemFileCacheInformation=21,
 SystemCacheInformation=21,
 SystemPoolTagInformation=22,
 SystemInterruptInformation=23,
 SystemProcessorStatistics=23,
 SystemDpcBehaviourInformation=24,
 SystemDpcInformation=24,
 SystemFullMemoryInformation=25,
 SystemNotImplemented6=25,
 SystemLoadImage=26,
 SystemUnloadImage=27,
 SystemTimeAdjustmentInformation=28,
 SystemTimeAdjustment=28,
 SystemSummaryMemoryInformation=29,
 SystemNotImplemented7=29,
 SystemNextEventIdInformation=30,
 SystemNotImplemented8=30,
 SystemEventIdsInformation=31,
 SystemNotImplemented9=31,
 SystemCrashDumpInformation=32,
 SystemExceptionInformation=33,
 SystemCrashDumpStateInformation=34,
 SystemKernelDebuggerInformation=35,
 SystemContextSwitchInformation=36,
 SystemRegistryQuotaInformation=37,
 SystemLoadAndCallImage=38,
 SystemPrioritySeparation=39,
 SystemPlugPlayBusInformation=40,
 SystemNotImplemented10=40,
 SystemDockInformation=41,
 SystemNotImplemented11=41,
 /* SystemPowerInformation=42, Conflicts with POWER_INFORMATION_LEVEL 1 */
 SystemInvalidInfoClass2=42,
 SystemProcessorSpeedInformation=43,
 SystemInvalidInfoClass3=43,
 SystemCurrentTimeZoneInformation=44,
 SystemTimeZoneInformation=44,
 SystemLookasideInformation=45,
 SystemSetTimeSlipEvent=46,
 SystemCreateSession=47,
 SystemDeleteSession=48,
 SystemInvalidInfoClass4=49,
 SystemRangeStartInformation=50,
 SystemVerifierInformation=51,
 SystemAddVerifier=52,
 SystemSessionProcessesInformation=53,
 SystemInformationClassMax
} SYSTEM_INFORMATION_CLASS;

typedef struct _SYSTEM_HANDLE_INFORMATION {
 ULONG ProcessId;
 UCHAR ObjectTypeNumber;
 UCHAR Flags;
 USHORT Handle;
 PVOID Object;
 ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

typedef struct _SYSTEM_ALL_HANDLES_INFORMATION {
 ULONG NumberOfHandles;
 SYSTEM_HANDLE_INFORMATION *SystemHandleInformation;
} SYSTEM_ALL_HANDLES_INFORMATION;

typedef NTSTATUS (NTAPI *NTQUERYSYSTEMINFORMATION)(
 IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
 IN OUT PVOID SystemInformation,
 IN ULONG SystemInformationLength,
 OUT PULONG ReturnLength OPTIONAL);

typedef enum _DEBUG_CONTROL_CODE {
 DebugGetTraceInformation=1,
 DebugSetInternalBreakpoint,
 DebugSetSpecialCall,
 DebugClearSpecialCalls,
 DebugQuerySpecialCalls,
 DebugDbgBreakPoint,
 DebugMaximum,
 DebugReadVirtualMemory,
 DebugWriteVirtualMemory
} DEBUG_CONTROL_CODE;

typedef NTSTATUS (NTAPI *NTSYSTEMDEBUGCONTROL)(
 IN DEBUG_CONTROL_CODE ControlCode,
 IN PVOID InputBuffer OPTIONAL,
 IN ULONG InputBufferLength,
 OUT PVOID OutputBuffer OPTIONAL,
 IN ULONG OutputBufferLength,
 OUT PULONG ReturnLength OPTIONAL);

typedef struct _MEMORY_CHUNKS {
 PVOID VirtualAddress;
 PVOID Buffer;
 ULONG BufferSize;
} MEMORY_CHUNKS, *PMEMORY_CHUNKS;

typedef LONG NTSTATUS; 
typedef LONG KPRIORITY; 
typedef ULONG_PTR KAFFINITY; 

typedef enum _PROCESS_INFORMATION_CLASS { 
 ProcessBasicInformation,         // 0 Y N 
 ProcessQuotaLimits,              // 1 Y Y 
 ProcessIoCounters,               // 2 Y N 
 ProcessVmCounters,               // 3 Y N 
 ProcessTimes,                    // 4 Y N 
 ProcessBasePriority,             // 5 N Y 
 ProcessRaisePriority,            // 6 N Y 
 ProcessDebugPort,                // 7 Y Y 
 ProcessExceptionPort,            // 8 N Y 
 ProcessAccessToken,              // 9 N Y 
 ProcessLdtInformation,           // 10 Y Y 
 ProcessLdtSize,                  // 11 N Y 
 ProcessDefaultHardErrorMode,     // 12 Y Y 
 ProcessIoPortHandlers,           // 13 N Y 
 ProcessPooledUsageAndLimits,     // 14 Y N 
 ProcessWorkingSetWatch,          // 15 Y Y 
 ProcessUserModeIOPL,             // 16 N Y 
 ProcessEnableAlignmentFaultFixup,// 17 N Y 
 ProcessPriorityClass,            // 18 N Y 
 ProcessWx86Information,          // 19 Y N 
 ProcessHandleCount,              // 20 Y N 
 ProcessAffinityMask,             // 21 N Y 
 ProcessPriorityBoost,            // 22 Y Y 
 ProcessDeviceMap,                // 23 Y Y 
 ProcessSessionInformation,       // 24 Y Y 
 ProcessForegroundInformation,    // 25 N Y 
 ProcessWow64Information          // 26 Y N 
} PROCESS_INFORMATION_CLASS;

typedef struct _UNICODE_STRING {
 USHORT Length;
 USHORT MaximumLength;
 PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _RTL_USER_PROCESS_PARAMETERS {
 BYTE Reserved1[56];
 UNICODE_STRING ImagePathName;
 UNICODE_STRING CommandLine;
 BYTE Reserved2[92];
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

typedef struct _PEB_LDR_DATA {
 BYTE Reserved1[20];
 LIST_ENTRY InMemoryOrderModuleList;
 BYTE Reserved2[8];
} PEB_LDR_DATA, *PPEB_LDR_DATA;

typedef struct _PEB {
 BYTE Reserved1[2];
 BYTE BeingDebugged;
 BYTE Reserved2[9];
 PPEB_LDR_DATA LoaderData;
 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
 BYTE Reserved3[448];
 ULONG SessionId;
} PEB, *PPEB;

typedef struct _PROCESS_BASIC_INFORMATION {
 NTSTATUS ExitStatus;
 PPEB PebBaseAddress;
 KAFFINITY AffinityMask;
 KPRIORITY BasePriority;
 ULONG UniqueProcessId;
 ULONG InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;

typedef NTSTATUS (NTAPI *NTQUERYINFORMATIONPROCESS)(
 IN HANDLE ProcessHandle,
 IN PROCESS_INFORMATION_CLASS ProcessInformationClass,
 OUT PVOID ProcessInformation,
 IN ULONG ProcessInformationLength,
 OUT PULONG ReturnLength);

typedef PVOID  PEPROCESS;

NTQUERYSYSTEMINFORMATION NtQuerySystemInformation;
NTSYSTEMDEBUGCONTROL NtSystemDebugControl;
NTQUERYINFORMATIONPROCESS NtQueryInformationProcess;
ULONG PidOffset;
ULONG PLinkOffset;

NTSTATUS KdReadVirtualMemory(PVOID VirtualAddress, PVOID Buffer, ULONG BufferSize)
{
 MEMORY_CHUNKS MemoryChunks;
 MemoryChunks.VirtualAddress=VirtualAddress;
 MemoryChunks.Buffer=Buffer;
 MemoryChunks.BufferSize=BufferSize;
 return NtSystemDebugControl(DebugReadVirtualMemory, &MemoryChunks, sizeof(MemoryChunks),
  NULL, 0, NULL);
}

NTSTATUS KdWriteVirtualMemory(PVOID VirtualAddress, PVOID Buffer, ULONG BufferSize)
{
 MEMORY_CHUNKS MemoryChunks;
 MemoryChunks.VirtualAddress=VirtualAddress;
 MemoryChunks.Buffer=Buffer;
 MemoryChunks.BufferSize=BufferSize;
 return NtSystemDebugControl(DebugWriteVirtualMemory, &MemoryChunks, sizeof(MemoryChunks),
  NULL, 0, NULL);
}

ULONG KdGetProcessId(HANDLE ProcessHandle)
{
 PROCESS_BASIC_INFORMATION ProcessInformation;
 if(NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation,
  &ProcessInformation, sizeof(PROCESS_BASIC_INFORMATION), NULL)>=0)
 {
  return (ULONG)ProcessInformation.UniqueProcessId;
 }
 return 0;
}

ULONG GetProcessIdOffset(PEPROCESS Process, HANDLE ProcessHandle)
{
 ULONG *Buffer=(PULONG)malloc(4096), ProcessId, Offset;
 memset(Buffer, 0, 4096);
 KdReadVirtualMemory(Process, Buffer, 4096);
 ProcessId=KdGetProcessId(ProcessHandle);
 if(!ProcessId)
 {
  free(Buffer);
  return 0;
 }
 for(Offset=0;Offset<4096;Offset++)
 {
  if(*(PULONG)((PCHAR)Buffer+Offset)==ProcessId)
  {
   free(Buffer);
   return Offset;
  }
 }
 free(Buffer);
 return 0;
}

ULONG GetProcessIdOffsetEx()
{
 ULONG NumberOfHandles, HandleIndex;
 ULONG *SystemInformation=(ULONG *)malloc(sizeof(SYSTEM_HANDLE_INFORMATION)+sizeof(ULONG));
 //미리 핸들을 하나 열어둔다.
 OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
    if(NtQuerySystemInformation(SystemHandleInformation, SystemInformation, sizeof(SYSTEM_HANDLE_INFORMATION)+sizeof(ULONG), 0)<0)
 {
  NumberOfHandles=*SystemInformation;
  free(SystemInformation);
  SystemInformation=(PULONG)malloc(NumberOfHandles*sizeof(SYSTEM_HANDLE_INFORMATION)+sizeof(ULONG));
 }
 NtQuerySystemInformation(SystemHandleInformation, SystemInformation, NumberOfHandles*sizeof(SYSTEM_HANDLE_INFORMATION)+sizeof(ULONG), 0);
 NumberOfHandles=*SystemInformation;
 printf("Number Of Handles : %d\n", NumberOfHandles);
 
 PSYSTEM_HANDLE_INFORMATION SystemHandleList=(PSYSTEM_HANDLE_INFORMATION)(SystemInformation+1);
 for(HandleIndex=0;HandleIndex<NumberOfHandles;HandleIndex++)
 {
  if(SystemHandleList[HandleIndex].ObjectTypeNumber==5 &&
   SystemHandleList[HandleIndex].ProcessId==GetCurrentProcessId())
  {
   ULONG Offset=GetProcessIdOffset(
    SystemHandleList[HandleIndex].Object,
    (HANDLE)SystemHandleList[HandleIndex].Handle);
   CloseHandle((HANDLE)SystemHandleList[HandleIndex].Handle);
   free(SystemInformation);
   return Offset;
  }
 }
 free(SystemInformation);
 return 0;
}

BOOL SetProcessId(ULONG ProcessId, ULONG NewProcessId)
{
 ULONG NumberOfHandles, HandleIndex;
  HANDLE ProcessHandle;
 ULONG *SystemInformation;
 //핸들을 미리 열어 둔다.
 ProcessHandle=OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
 if(!ProcessHandle)
 {
  return FALSE;
 }
 SystemInformation=(ULONG *)malloc(sizeof(SYSTEM_HANDLE_INFORMATION)+sizeof(ULONG));
 if(NtQuerySystemInformation(SystemHandleInformation, SystemInformation, sizeof(SYSTEM_HANDLE_INFORMATION)+sizeof(ULONG), 0)<0)
 {
  NumberOfHandles=*SystemInformation;
  free(SystemInformation);
  SystemInformation=(PULONG)malloc(NumberOfHandles*sizeof(SYSTEM_HANDLE_INFORMATION)+sizeof(ULONG));
 }
 NtQuerySystemInformation(SystemHandleInformation, SystemInformation, NumberOfHandles*sizeof(SYSTEM_HANDLE_INFORMATION)+sizeof(ULONG), 0);
 NumberOfHandles=*SystemInformation;
 
 PSYSTEM_HANDLE_INFORMATION SystemHandleList=(PSYSTEM_HANDLE_INFORMATION)(SystemInformation+1);
 printf("PID\tHANDLE\tObject\t\tFlags\tAccess\tObjectType\n");
 printf("-----------------------------------------------------------\n");
 for(HandleIndex=0;HandleIndex<NumberOfHandles;HandleIndex++)
 {
  //ObjectTypeNumber=5이면 프로세스, 6이면 스레드
  if(SystemHandleList[HandleIndex].ObjectTypeNumber==5 &&
   SystemHandleList[HandleIndex].ProcessId==GetCurrentProcessId() &&
   (HANDLE)SystemHandleList[HandleIndex].Handle==ProcessHandle)
  {
   //EPROCESS의 주소는 Object에 있다.
   //EPROCESS::UniqueProcessId에 NewProcessId의 값으로 채운다.
   KdWriteVirtualMemory(
    (PCHAR)SystemHandleList[HandleIndex].Object+PidOffset,
    &NewProcessId,
    4);
   printf("%d\t%x\t%x\t%x\t%x\t%x\n",
    SystemHandleList[HandleIndex].ProcessId,
    SystemHandleList[HandleIndex].Handle,
    SystemHandleList[HandleIndex].Object,
    SystemHandleList[HandleIndex].Flags,
    SystemHandleList[HandleIndex].GrantedAccess,
    SystemHandleList[HandleIndex].ObjectTypeNumber);
   CloseHandle((HANDLE)SystemHandleList[HandleIndex].Handle);
   free(SystemInformation);
   return TRUE;
  }
 }
 free(SystemInformation);
}

BOOL SetDebugPrivilege()
{
 HANDLE TokenHandle;
 LUID Luid;
 TOKEN_PRIVILEGES TokenPrivileges;
 if(!OpenProcessToken((HANDLE)0xFFFFFFFF, TOKEN_ALL_ACCESS, &TokenHandle))
 {
  return FALSE;
 }
// LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid);
 Luid.LowPart=20;
 Luid.HighPart=0;
 TokenPrivileges.PrivilegeCount=1;
 TokenPrivileges.Privileges->Attributes=SE_PRIVILEGE_ENABLED;
 TokenPrivileges.Privileges->Luid=Luid;
 if(!AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES),
  NULL, NULL))
 {
  CloseHandle(TokenHandle);
  return FALSE;
 }
 CloseHandle(TokenHandle);
 return TRUE;
}

void main()
{
 ULONG ProcessId, NewProcessId;
 NtQuerySystemInformation=(NTQUERYSYSTEMINFORMATION)
  GetProcAddress(LoadLibrary("ntdll.dll"), "NtQuerySystemInformation");
 NtSystemDebugControl=(NTSYSTEMDEBUGCONTROL)
  GetProcAddress(LoadLibrary("ntdll.dll"), "NtSystemDebugControl");
 NtQueryInformationProcess=(NTQUERYINFORMATIONPROCESS)
  GetProcAddress(LoadLibrary("ntdll.dll"), "NtQueryInformationProcess");
 SetDebugPrivilege();
 PidOffset=GetProcessIdOffsetEx();
 PLinkOffset=PidOffset+0x04;
 printf("변경할 프로세스 아이디 입력\n");
 scanf("%d", &ProcessId);
 printf("새로운 프로세스 아이디 입력\n");
 scanf("%d", &NewProcessId);
 SetProcessId(ProcessId, NewProcessId);
 FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
 printf("원래대로 하려면 아무키나 누르시오\n");
 getch();
 SetProcessId(ProcessId, ProcessId);
}

Posted by skensita
Programming/Win32 API2008. 12. 3. 10:52
먼저 QueryPerformanceFrequency로 1초에 몇회인지를 구합니다.
그런 다음 QueryPerformanceCounter로 현재의 카운트를 구합니다.
Counter를 Frequency로 나누면 초단위의 경과 시간이 됩니다.

LARGE_INTEGER freq, start, end;
unsigned lapse;

QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&start);
 
//경과시간을 측정할 작업을
//이부분에서 하고

QueryPerformanceCounter(&end);

lapse = (unsigned) ((end.QuadPart - start.QuadPart)/freq.QuadPart);

//lapse에는 초단위의 경과 시간이 저장됨.
 
Posted by skensita
Programming/Win32 API2008. 12. 3. 10:07

제가 중점적으로 설명하려는 API는 다음과 같습니다.

ExitWindowsEx

InitiateSystemShutdown

NtShutdownSystem

 

먼저, ExitWindowsEx() 에 관하여 알아봅시다.

이 함수는 성공시 TRUE, 실패시 FALSE를 반환합니다.

WINUSERAPI

BOOL

WINAPI

ExitWindowsEx(

    DWORD dwFlags,

    DWORD dwReserved);

 

dwFlags에는 일반적으로 다음과 같은 상수들이 들어갑니다.

EWX_LOGOFF : 시스템을 로그오프시킨다.
EWX_SHUTDOWN : 시스템을 종료시킨다. (전원이 꺼지지 않는경우도 있다)
EWX_REBOOT : 시스템을 재시작시킨다.
EWX_FORCE : 이 옵션이 들어가면 실행중인 프로그램을 강제종료한다
EWX_POWEROFF : 이 옵션이 들어가면 전원을 완전히 끈다.
그리고, 이 상수들은 조합해서 쓸 수도 있습니다.

예를 들면, "실행중 프로그램을 강제종료시키고 시스템을 종료하고 싶다" 면,

dwFlags에는 EWX_SHUTDOWN | EWX_FORCE가 들어가면 되는 것입니다.

 

dwReserved에는 0xFFFFFFFF가 들어가는 것 같습니다.

헤더 파일에도 정의된 것이 있긴 있는것 같습니다.

#define ExitWindows(dwReserved, Code) ExitWindowsEx(EWX_LOGOFF, 0xFFFFFFFF)

자 이번에는 InitiateSystemShutdown()에 대해 알아보겠습니다.

이 함수는 호출시 프로세스 winlogon.exe에 시스템 종료 Message가 담긴 창을 띄워서

시스템 종료까지의 남은 시간을 표시해 줍니다. 남은 시간이 0:00:00이 되면, 시스템은 종료됩니다.

성공시 TRUE, 실패시 FALSE를 반환합니다.

여기서부터 나오는 함수는, Windows 9x는 지원하지 않습니다!!!!

WINADVAPI
BOOL
WINAPI
InitiateSystemShutdownA(
    IN LPSTR lpMachineName,
    IN LPSTR lpMessage,
    IN DWORD dwTimeout,
    IN BOOL bForceAppsClosed,
    IN BOOL bRebootAfterShutdown);

lpMachineName : 종료할 컴퓨터의 이름으로 보여집니다. 일반적으로 NULL

lpMessage : 시스템 종료시 띄울 Message

dwTimeout : 시스템 종료까지의 시간(초)

bForceAppsClosed : 시스템 종료시 프로그램을 강제종료할 것인가의 여부.

bRebootAfterShutdown : 시스템 종료 후에 재부팅 할것인지의 여부

또한, 이 함수로 시작된 시스템 종료는, 시스템 종료까지의 시간이 만기되기 전에 취소할 수 있는데,

이 역할을 하는 함수가 AbortSystemShutdown()입니다.

WINADVAPI

BOOL

WINAPI

AbortSystemShutdownA(

    IN LPSTR lpMachineName);

lpMachineName : 위의 설명과 같다.

 

이제는 좀 특별한 API인 NtShutdownSystem() 에 대해 알아보겠습니다.

이 함수는 다른 함수와는 좀 달리, 설정 저장 없이, 바로 시스템을 종료시킵니다.

성공시 STATUS_SUCCESS를 반환합니다.

STATUS_SUCCESS는 다음으로 정의됩니다:

#define STATUS_SUCCESS            (NTSTATUS)0

NTSYSAPI

NTSTATUS

NTAPI

NtShutdownSystem(

    IN SHUTDOWN_ACTION ShutdownAction);

ShutdownAction : 종료방법(말하자면 옵션).

SHUTDOWN_ACTION은 enum으로 되어있습니다.

typedef enum _SHUTDOWN_ACTION {
    ShutdownNoReboot,
    ShutdownReboot,
    ShutdownPowerOff
} SHUTDOWN_ACTION, *PSHUTDOWN_ACTION;
ShutdownNoReboot : 시스템을 종료하나, 재시작하지 않는다. (전원은 꺼지지 않는 것 같다.)

ShutdownReboot : 시스템을 재시작한다.

ShutdownPowerOff : 시스템 종료 후 전원을 끈다. 만일 하드웨어가 이 기능을 지원하지 않으면,  ShutdownReboot를 수행한다.

 

하지만, Windows NT/2K/XP/... 등에서 이를 사용하기 위해서는 Shutdown 권한이 있어야 합니다.

따라서, 권한을 얻어야 하는데, 그 일을 하는 함수가 바로, NTDLL.DLL의 RtlAdjustPrivilege()입니다.

OpenProcessToken()->LookupPrivilegeValue()->AdjustTokenPrivileges() 를 하는 방법도 있지만,

여기에서는 글이 약간 길어지므로 이 글에서는 다루지 않도록 하겠습니다.

NTSYSAPI

NTSTATUS

NTAPI

RtlAdjustPrivilege(

    ULONG Privilege,
    BOOL bEnable,
    BOOL bIsCurrentThread,
    PULONG PreviousPrivilege);
Privilege : LookupPrivilegeValue()로 얻어온 권한의 값(좀 설명이 애매하군요). Index.

bEnable : 권한을 설정할것인지의 여부. 일반적으로 TRUE.

bIsCurrentThread : 현재 쓰레드에 대하여인지의 여부. (테스트 결과, FALSE를 선택하면 프로세스 전체에 대해서인것 같다.)

일반적으로 FALSE.

PreviousPrivilege : 이전의 권한이 이 인자로 넘어온다.

예를 들어서, Debug 권한을 얻고 싶으면

ULONG PreviousPrivilege;

RtlAdjustPrivilege(20, TRUE, FALSE, &PreviousPrivilege)

를 해주면 될겁니다.

 

이상으로, 시스템 종료에 관한 몇몇 API와 그 쓰임에 대해 알아보았습니다.

Posted by skensita
Programming/Win32 API2008. 12. 3. 10:05

DLL Injection - 참고

Posted 2007/06/19 14:16, Filed under: Study/Computer Science
================================================================================
Title : DLL Injection

Author : proXima
Contact : proxima ]at[ postech.ac.kr
Date : 2006/11/15 - 2006/11/15
================================================================================

2부에서 DLL Injection에 대해 간단하게 언급했었다. 이번 글에서는 DLL Injection이 무엇인지, 어떤 방법으로 이루어질 수 있는지를 알아보도록 하자.

일단, DLL Injection이 무엇인지부터 간단하게 알아보는 것이 좋을 것 같다.
단어 그대로 해석해 보자면, DLL Injection이라는 것은 'DLL 주입'이라는 뜻을 가지는데, 그냥 이 말만 가지고는 뜻이 명확하지가 않다. DLL을 주입한다고? 그게 무슨 뜻이지?

1. DLL을 주입하다
다들 알고 있겠지만(몰랐다면 앞으로 알면 좋다), 프로세스는 실행파일 하나만 메모리에 달랑 올린다고 실행이 되는 것이 아니라, 실행에 필요한 동적 라이브러리들을 같이 메모리에 올려야만 실행이 가능하다. DLL이라는 것은 Windows에서 제공하는 동적 라이브러리 형태로서, 리눅스에서의 .so 파일과 같은 역할을 한다고 보면 된다.
방금 설명했듯이, 동적 라이브러리도 프로세스의 메모리 공간에 올라가게 되는데, 디버거를 통해 확인해 보면 아마 보통 ntdll.dll, kernel32.dll, user32.dll 등의 dll 파일들이 프로세스의 실행파일 이미지와 같이 메모리에 올라가 있는 것을 확인할 수 있을 것이다.
DLL은 실행파일과 비슷하다. 그 자체로 실행파일이 되지 않는다는 것을 제외한다면, 파일의 내부는 실행파일과 다른 점이 없다. (.exe 파일도 함수를 export할 수 있다.)
그러면 DLL을 다른 프로세스에 주입한다는 게 무슨 뜻인가 하면... 다른 프로세스의 메모리 공간에 내가 만든 DLL을 매핑한다는 뜻이다. 하지만 단순이 메모리에 DLL을 매핑하는 것이 다는 아니다. DLL이 로드될 때 자동으로 실행되는 DllMain 에서 내가 원하는 코드를 '다른 프로세스 내에서' 실행시킬 수도 있다. 바로 이게 핵심이다.
DLL Injection을 통해 내가 원하는 코드를 '다른 프로세스 내에서' 실행시킬 수 있다.


2. 이게 어째서 가능한가
앞에서 이것저것 설명했었지만, 이게 가능한 이유는 Windows가 다음와 같은 환경을 제공해 주기 때문이다.
1) 런타임에 동적으로 DLL 파일을 로드할 수 있다.
2) 다른 프로세스의 메모리 공간에 데이터를 쓸 수 있다.
3) 다른 프로세스에서 함수를 실행시킬 수 있다
4) DLL이 로드될 때 로드된 DLL 파일 내의 DllMain 함수가 실행된다!


3. DLL Injection을 발생시키는 과정
Windows에서는 프로세스가 런타임에 동적으로 DLL 파일을 로드하도록 해 주는 LoadLibrary라는 함수가 있다. 그리고 다른 프로세스에서 그 LoadLibrary를 실행할 수가 있다. 그렇다면 내가 DLL을 만든 뒤에 그 DLL을 다른 프로세스에서 LoadLibrary를 통해 로드하도록 하면, 내가 만든 DLL을 주입할 수 있는 것이다.
그렇다면 어떻게 다른 프로세스에서 함수를 실행시킬 수 있을까? 바로 CreateRemoteThread라는 함수를 이용하는 것이다. CreateRemoteThread는 다른 프로세스 내에 새로운 쓰레드를 생성시키는데, 그 생성된 쓰레드로 하여금 어떤 함수를 실행하게 할 것인지를 인자로 넘길 수 있다.
그렇기 때문에 CreateRemoteThread를 이용하여 LoadLibrary를 실행하게 한다면, 내가 만든 DLL의 DllMain이 실행된다.
하지만 넘어가야 하는 난관이 조금 있는데, 일단 CreateRemoteThread와 LoadLibrary의 프로토타입을 보자.


HANDLE CreateRemoteThread(  HANDLE hProcess,
 LPSECURITY_ATTRIBUTES lpThreadAttributes,
 SIZE_T dwStackSize,
 LPTHREAD_START_ROUTINE lpStartAddress,
 LPVOID lpParameter,
 DWORD dwCreationFlags, 
 LPDWORD lpThreadId
);

HMODULE LoadLibrary(
  LPCTSTR lpFileName
);

 
프로토타입을 보면서 조금 더 설명을 하자면, DLL Injection이 가능한 이유는, LoadLibrary가 인자를 '단 하나'만 받기 때문이다. CreateRemoteThread는 쓰레드를 새로 만들면서 쓰레드로 실행되는 함수에게 인자를 하나 넘길 수 있는데, LoadLibrary는 아주 다행스럽게 인자를 '단 하나'만 받는다.

하지만, LoadLibrary를 실행하기 위해서는 '로드할 DLL 파일명'을 LoadLibrary의 인자로 넘겨주어야 한다. 그렇다면 다른 프로세스의 메모리 공간에 내가 원하는 '로드할 DLL 파일명'을 써 넣어야 하는데, 그것은 이 전에 쓴 글인 'Controlling Memory Space of Other Process'에서 언급했듯이, Windows 에서 제공해 주는 API들을 사용해서 가능하게 할 수 있다.

그렇다고 하더라도 가장 큰 문제가 있는데, 그게 무엇인가 하면 바로 LoadLibrary의 주소는 '타겟 프로세스'의 가상메모리 상에서의 주소여야 한다는 점이다. 알고 있다시피, DLL들은 프로그램이 실행될 때마다 다른 메모리 주소에 매핑될 수 있는데, 그것 때문에 타겟 프로세스의 LoadLibrary가 어떤 주소에 위치하는지를 모른다면 이것은 말짱 꽝이 될 수도 있다.
그래도 이걸 해결하는 방법이 있다. 다른 프로세스의 메모리를 읽어 kernel32.dll 이 그 프로세스의 어느 메모리 주소에 위치하는지 알아내고, 그 kernel32.dll 이 export하는 함수들을 읽으면서 LoadLibrary의 주소가 어디 있는지 알아낼 수 있다. 뭐 그 밖에도 다른 방법도 있을 수 있지만, 지금은 이게 문제가 되지 않는다. 왜냐하면...

서로 다른 프로세스라도 kernel32.dll 은 가상메모리 상에서 거의 항상 같은 메모리 주소에 매핑되기 때문에, 그냥 내 프로세스의 LoadLibrary 주소를 넘기면 된다.


4. 코드를 짜 보자


HANDLE hProcess;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

LPVOID pFileName;
pFileName = HeapAlloc(NULL, strlen(fileName)+1, MEM_COMMIT, \
                             PAGE_READWRITE);

WriteProcessMemory(hProcess, pFileName, fileName, strlen(fileName)+1, \
                   &nWritten);

HANDLE hRemoteThread;
hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, \
                                   (LPTHREAD_START_ROUTINE)LoadLibrary,
                                   pFileName, 0, NULL);

CloseHandle(hRemoteThread);
CloseHandle(hProcess);
 

이제 DLL Injection 을 할 수가 있게 됐다. 내가 DLL을 만들어서 다른 프로세스에 넣어보자. 실제로 스피드핵의 경우 timeGetTime 함수를 뺏는 역할을 하는 DLL을 프로세스에 주입함으로써 빠르게 돌아가게 하는 방법도 사용하는 프로그램도 있다.

다른 프로세스의 내부에 내가 원하는 코드를 집어넣는다는 것은 굉장히 강력할 수 있다. 때문에 악용될 경우 큰 피해가 날 수도 있는데, 아무쪼록 좋은 곳에 사용하길 바란다.
Posted by skensita
Programming/Win32 API2008. 12. 3. 10:04

음......이번에는 프로세스 목록을 얻어오는 방법에 대해서 아주~간단히 알아보도록 하겠습니다.

프로세스 목록을 얻어오는 방법 중 간단히 2가지를 소개하자면,

첫째로, CreateToolhelp32Snapshot/Process32First/Process32Next 를 이용하는 간단한 방법입니다.

둘째로, NtQuerySystemInformation을 이용하는 방법이 있으나, 이 방법을 추가하면 코드가 약간 길어지므로 나중에 설명하겠습니다. [NT/2K/XP/2K3/Vista/...에서만 호환]

 

여기에서 소개하려는 주요 API는 다음과 같습니다. [Win9x에서도 호환됩니다.]

 

CreateToolhelp32Snapshot

Process32First

Process32Next

 

자, CreateToolhelp32Snapshot() 에 관해 알아봅시다.

이 API는 스냅샷 핸들을 얻어오는 역할을 합니다.

성공시 "올바른" 핸들을 반환합니다.

(잘못된 핸들로 취급되는 예:핸들 값이 NULL인 경우, 혹은 INVALID_HANDLE_VALUE(0xFFFFFFFF))

그리고 이렇게 얻어진 핸들의 사용이 끝나면, 다시 CloseHandle() API를 이용하여 핸들을 닫아주는게 좋습니다.

WINBASEAPI

HANDLE

WINAPI

CreateToolhelp32Snapshot(

     IN DWORD th32Flags,

     IN DWORD th32ProcessID);

th32Flags : TH32CS_SNAPPROCESS, TH32CS_SNAPMODULE, ...등의 상수가 있는데,

프로세스 목록을 얻으려면 TH32CS_SNAPPROCESS를, 모듈 목록을 얻으려면 TH32CS_SNAPMODULE, ....등을 넣으면 되는것 같습니다. 이 외에도 TH32CS_SNAPTHREAD, TH32CS_SNAPHEAPLIST가 있습니다.

이 상수를 이용해 얻어진 핸들은 일반적으로, Xxx32First/Xxx32Next 루틴으로 목록을 얻어올 수 있습니다.

예를 들어서, TH32CS_SNAPPROCESS를 인자로 사용하였다면, Process32First()/Process32Next() 루틴으로 목록을 얻어올 수 있는 것입니다.

th32ProcessID : 이 인자는 "여기에서는" 0을 줘도 무방합니다. 제 생각에는 Toolhelp32ReadProcessMemory() API와 관련이 있는 인자이기도 하지 않을까 싶군요. 여기에 유효한 Process ID를 인자로 주면 해당 Process ID에 해당하는 Process의 정보를 얻어 올 수 있지 않을까도 싶고요.

 

이제는 Process32First/Process32Next 에 관해 알아보겠습니다.

Process32First는 오직 첫번째 프로세스의 정보만을 가져옵니다.

그리고 Process32Next는 다음 프로세스가 없을 때까지 찾아서 다음 프로세스를 찾으면 정보를 가져오고, TRUE를 반환합니다.

인자는 똑같습니다.

둘 다, 성공시 TRUE를, 실패시 혹은 더이상 프로세스가 없을 시에는 FALSE를 반환합니다.

WINBASEAPI

BOOL

WINAPI

Process32First(

     IN HANDLE hSnapshot,

     OUT PPROCESSENTRY32 lpProcessEntry32Info);

WINBASEAPI

BOOL

WINAPI

Process32Next(

     IN HANDLE hSnapshot,

     OUT PPROCESSENTRY32 lpProcessEntry32Info);

hSnapshot : CreateToolhelp32Snapshot() 로 얻어온 "올바른" 스냅샷 핸들.

lpProcessEntry32Info : PROCESSENTRY32 의 포인터형. 만일 성공시 이 인자로 프로세스 정보가 넘어옵니다.

Process32First() 호출시, PROCESSENTRY32 구조체에는 반드시 PROCESSENTRY32::dwSize에 sizeof(PROCESSENTRY32) 를 넣어줘야 합니다.

 

으음 그리고 이것은 보너스.

이 API는 핸들을 닫는 역할을 하며, 성공시 TRUE, 실패시 FALSE를 반환합니다.

WINBASEAPI

BOOL

WINAPI

CloseHandle(

    IN HANDLE hHandle);

hHandle : OpenProcess()/OpenFile()/CreateFile()/CreateToolhelp32Snapshot()/CreateFileMapping()/OpenFileMapping().... 등을 이용해서 얻어진 핸들. (FindWindow()로 얻어진 윈도우 핸들이나 GDI Object 등등은 포함되지 않습니다!)

 

이상 프로세스 목록을 얻는 데 필요한 API에 대해 대강 알아보았으므로, 한번 짜보겠습니다.

 

#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>
void PrintProcessList()
{
   HANDLE hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
   if(hSnapshot)
   {
        PROCESSENTRY32 ProcessEntry32;
        BOOL bProcessFound;
        ProcessEntry32.dwSize=sizeof(PROCESSENTRY32);
        bProcessFound=Process32First(hSnapshot, &ProcessEntry32);
        while(bProcessFound)
        {
             printf("%s [%d]\n", ProcessEntry32.szExeFile, ProcessEntry32.th32ProcessID);
             bProcessFound=Process32Next(hSnapshot, &ProcessEntry32);
        }
        CloseHandle(hSnapshot);
    }
}
void main()
{
     PrintProcessList();
}

 

어떤가요? 코드가 생각보다 짧지 않나요?

어쨌거나 이상으로, 프로세스 목록을 얻어오는 간단한 방법에 대해서 알아보았습니다.

Posted by skensita
Programming/Win32 API2008. 12. 1. 15:46
이 역시 생각지도 못한 버그를 만들어 오랫동안 골치를 썩였기에 여러분은 이러지 마시라고 올립니다.

LPTSTR lstrcpyn(
 LPTSTR lpString1,  // destination buffer
 LPCTSTR lpString2, // string
 int iMaxLength     // number of characters to copy ★
);

★ 중요한 건 3번째 인자인데 예를 들면
   lstrcpyn(buf, "abcdef", 3); 하면 buf 는 "abc"가 아니라 "ab" 가 된다는 것입니 다.
   즉 주석에는 number of characters to copy 라고 되어있지만 ★ 이 안에 null 을 위한 갯수가 포함되어있음을 주의해야 합니다.

★ 이 세번째 인자는, 주석을 읽어보면 얼핏 "몇 글자를 copy할 것인가" 를 말하는 것처럼 보이지만,
   이보다는 buffer의 한계를 넘어 copy되지 못하도록 보호벽을 치는 의미이므로,
   copy할 문자열이 아닌 "buffer의 사이즈"와 연관지어 생각해야 합니다.
- 다음과 같이 사용.
      CHAR buf[256];
      lstrcpyn(buf, "복사할 문자열", 256); // 자동으로 NULL을 고려하여 실제로 255개 까지만 copy됨.

★ 참고로 표준 c runtime library 의 strncpy 는 이렇지 않음.
   strncpy(buf, "abcdef", 3); 하면 buf 는 "abc" 임.
- 이 경우는 다음과 같이 사용.
      char   buf[256];
      strncpy(buf, "복사할 문자열", 255); // buf가 포함할 수 있는 최대 길이 - 1 (NULL 고려해 주어야 함)
Posted by skensita
Programming/Win32 API2008. 12. 1. 15:44

데브피아의 이승규 님의 글을 허락도 없이 퍼왔습니다. (__)ㅋ

---------------------------------------------------------


쩝...유닉스랑은 부모와 자식관계가 참 거시기 하네요... 그냥 함 만들어 봤습니다. GetCurrentProcessId같은것들은 있는데 왜 이건 안만들어서 절 귀찮게 하는지 모르겠네요..-_-;
 
#include <Tlhelp32.h>
 
// 부모 프로세스 아이디
DWORD GetParentProcessId()
{
    HANDLE          hProcessSnap    = NULL;
    PROCESSENTRY32  pe32            = {0};
    DWORD           pid             = GetCurrentProcessId();
   
 
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == INVALID_HANDLE_VALUE)   {
        return FALSE;
    }
 
    pe32.dwSize = sizeof(PROCESSENTRY32);
 
    if (Process32First(hProcessSnap, &pe32))    {
        DWORD Code = 0;
        do{        
            if(pe32.th32ProcessID != pid) {
                continue;
            }           
            CloseHandle (hProcessSnap);
            return pe32.th32ParentProcessID;
        } while (Process32Next(hProcessSnap, &pe32));
    }
    CloseHandle (hProcessSnap);
    return 0;
}
 
// 부모프로세스 핸들
HANDLE GetParentProcessHandle()
{
    DWORD       dwParentProcessId;
    dwParentProcessId = GetParentProcessId();
    return OpenProcess (PROCESS_ALL_ACCESS, FALSE, dwParentProcessId);          
}
 
// 부모프로세스 끝나기 기다리기
void WaitForParentProcess(DWORD dwTimeout)
{
    HANDLE hParentProcess;
 
    hParentProcess = GetParentProcessHandle();
 
    if ( hParentProcess != NULL )
    {
        WaitForSingleObject(hParentProcess, dwTimeout);
        CloseHandle(hParentProcess);
 
        return ;
    }
}
 
// 부모 프로세스 죽이기
void TerminateParentProcess()
{
    HANDLE hParentProcess;
 
    hParentProcess = GetParentProcessHandle();
 
    if ( hParentProcess != NULL )
    {
        if (TerminateProcess(hParentProcess, 0))
        {
            CloseHandle(hParentProcess);
            return;
        }
 
        return ;
    }
}

주석으로 막아 놓은 것은 찾고자 하는 프로세스의 이름으로 프로세스를 찾아 그것의 상태를 보고 싶을때 쓸수 있습니다


SendMessageTimeout 대신 IsHungAppWindow라는 함수를 쓸 수 있다는 글을 어느 분이 쓰신것 같은데 저는 그 함수가 어느 헤더에 정의 되어져 있는지 알 수 가 없더군요

혹시 아시는 분 계시면 답글 달아 주시면 감사하겠습니다


위의 루틴은 비교적 쉬우니까 초보 분들도 이해 하시는데 어려움이 없을것 같네요


코딩은 쉽게 쉽게 짜여 졌으면 하는 바램으로 글을 올립니다

주석으로 막아 놓은 것은 찾고자 하는 프로세스의 이름으로 프로세스를 찾아 그것의 상태를 보고 싶을때 쓸수 있습니다


---------------------------------------------------------------------------------------

좋음 2004-06-17 13:49:00 user32.dll에 있는 함수죠... 문서화 되지 않은 함수입니다. 따라서 문서에 나와있지 않고
헤더에도 없죠... BOOL WINAPI IsHungAppWindow(HWND hwnd); 입니다. 직접 LoadLibrary해서
사용하시면 됩니다.
신영진
(hacsyj)
궁금 2004-06-18 09:01:00 문서화 되지 않은 함수인가요?
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/Windowing/Windows/WindowReference/WindowFunctions/IsHungAppWindow.asp
배토
(batmask)
좋음 2004-06-18 10:35:00 msdn에서 발췌
Function Information
Header Declared in Winuser.h, include Windows.h
Import library User32.lib
Minimum operating systems Windows 2000
심준석
(stonesim@hotmail.com)
좋음 2004-07-08 09:27:00 CreateToolhelp32Snapshot 으로 열린 핸들은 CloseToolhelp32Snapshot을 이용해
닫으라는군요. CloseHandle을 쓰면 메모리 leak이 있답니다. ^^
CloseHandleh(ProcessSnap) => CloseToolhelp32Snapshot(ProcessSnap)
배토
(batmask)
좋음 2004-07-13 16:45:00 CloseToolhelp32Snapshot은 VC7에서는 찾을 수가 없습니다. 김회대
(k5022)
좋음 2004-07-13 16:50:00 IsHungAppWindow은 다음과 같은 형식으로 사용하면 됩니다.
typedef BOOL (WINAPI *PROCISHUNGAPPWINDOW) (HWND);

PROCISHUNGAPPWINDOW IsHungAppWindow;
HMODULE hUser32 = GetModuleHandle("user32");
IsHungAppWindow = (PROCISHUNGAPPWINDOW)GetProcAddress(hUser32,"IsHungAppWindow");
김회대
(k5022)


Posted by skensita
Programming/Win32 API2008. 12. 1. 15:42

프로세스를 죽이는 방법은 여러가지가 있지만 남의 프로그램을 Class Name, Windows Name으로

Process Id를 얻어내어 프로세스를 Kill 시키는 방법을 기술한다.


참고로 Process Id와 Process Name 은 Spy++ 로 쉽게 확인 할수 있다.

또한 다이얼로그 기반 프로세스는 Windows Name이 없기 때문에 Null값을 입력하면 된다.


//먼저 핸들값을 얻어낸다.

hwnd = FindWindow(TEXT("Class Name"),TEXT("Windows Name"));

if(hwnd == NULL)
 {
  return false;

 }


//핸들값을 통해 ProecssId를 도출한다.

DWORD dwProcessId = NULL;
 GetWindowThreadProcessId( hwnd,    &dwProcessId);
 if(dwProcessId == NULL)
 {
    return false;
 }


HANDLE  process;
 DWORD  dwError;


//얻어진 ProcessId로 프로세서를 연다.
 process = OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessId );
 dwError = GetLastError();
 if(process == NULL)
 {
    if(dwError == ERROR_INVALID_PARAMETER) // already terminated.
       return true;

 
  return false;
 }


//열려진 Process핸들값으로 해당 프로세서를 종료한다.
 if(!TerminateProcess(process, (UINT)-1))
  printf("KillProcess: TerminateProcess returned false. PID = %u", id);

 CloseHandle(process);
 return true;



꼬리에 꼬리를 무는 식으로 프로그램이 짜여져 있다.

이런것들이 노가다성 작업으로 느껴지기도한다.

Posted by skensita