7월, 2018의 게시물 표시

CreateStreamOnHGlobal 예제

CreateStreamOnHGlobal () API는 HGlobal 메모리 핸들을 사용하는 stream object를 생성하는 API이다. 여기의 object는 OLE가 제공하는 IStream이다. 리턴되어진 스트림 객체는 트랜잭션을 지원하지 않으며, 영역 잠금을 지원하지 않는다고 하는데(영역 잠금이 뭐지?) #1(hGlobal) ; GlobalAlloc API가 리턴한 메모리 핸들. 새로운 메모리 핸들이 할당되는거면 NULL이 입력됨. NULL이 입력되지 않는 경우 스트림내용은 메모리 블럭의 현재 내용이다.  #2(fDeleteOnRelease) ; 스트림 객체가 해제될때 자동적으로 내제 핸들을 free해줄지 가리킴 #3(ppstm) ; 신규 스트림 객체를 받는 포인터 주소 설명 ; 스트림 객체와 연관된 메모리 핸들을 얻기 위해서 GetHGlobalFromStream API가 존재. 메모리 핸들을 넘겨서 IStream 객체를 생성 ---------------------------------------------------------------------------- HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE, iSize); LPVOID pImage = ::GlobalLock(hMem); // pImage operation... ::GlobalUnlock(hMem); IStream* pStream = NULL; if( ::CreateStreamOnHGlobal(hMem, TRUE, &pStream) == S_OK ) {    Image * pImage = Image::FromStream(pStream);    pStream->Release(); } ---------------------------------------------------------------------------- 신규메모리핸들 생성한 후에 메모리 블럭 내용...

[WinDbg] ntdll 심볼내용중 datatype 명시적으로 빠져 버렸음

대략 2015년 7월까지의 심볼파일에는 ntdll의 datatype이 노출되어 있었으나 8월부터의 심볼파일에는 datatype을 노출시키지 않음.(ntdll만 해당되는게 아니다) 따라서 !heap -s과 같은 명령을 수행하게 되면 정보가 표시되지 않는다. win7 / 64bit 에서 테스트 된 경우이고, win8은? 이전의 인스턴스 심볼파일을 명시적으로 로드하는데 차선책이라고 나와 있는데 .reload /f /i

[WinAPI] __declspec(naked) vs #pragma runtime_checks

컴파일러가 생성하는 프롤로그 에필로그를 명시적으로 생성하지 말아라! __declspec(naked) NTSTATUS Func1() { } 위와 똑같다! #pragma runtime_checks("[runtime_checks]", off) NTSTATUS Func1() { } #pragma runtime_checks("[runtime_checks], restore)

[WinDbg] StartAddress vs Win32StartAddress

StartAddress 는 CreateThread 내부적으로 사용하는 주소 -> 이게 필요한 이유는 ExitThread를 일괄적으로 해주기 위해서 Win32StartAddress 는 우리가 파라미터로 건넨(CreateThread 호출시) 바로 그 주소임. pContext->EAX = Win32StartAddress (WinMainCRTStartUp) AOEP와 동일 pContext->EIP = StartAddress (ntdll!RtlUserThreadStart와 동일)  ntdll!RtlUserThreadStart가 실행되고 WinMainCRTSartUp이 실행이 된다. ntdll!RtlUserThreadStart mov dword ptr[esp+4], eax ; eax = Win32StartAddress mov dword ptr[esp+8], ebx ; ebx = PEB jmp ntdll!_RtlUserThreadStart 00001010 00000000 EAX EBX ntdll!_RtlUserThreadStart mov edi, edi push ebp 0000100C EBP 00000000 EAX EBX mov ebp, esp ; ebp = 0000100C push ecx ; 아마도 0 push ecx 00001004 ecx ecx EBP 00000000 EAX EBX lea eax, [ebp-8] ; eax = 00010004 call ntdll!RtlInitializeExceptionChain push dword ptr[ebp+C] push dword ptr[ebp+8] 0000FFFC EAX EBX ecx ecx EBP 00000000 EAX EBX call ntdll!__RtlUserThreadStart 노트패드를 예로 들면) ETHREAD! Win32StartAddress 는 notepad!WinMa...

[WinAPI] (object *)0의 의미

구조체 레이아웃이 아래와 같이 되어 있는 경우에  typedef struct _TEST_STRUCT_  {   DWORD a;   DWORD b;   DWORD c;   DWORD d;  } *PTEST_STRUCT, TEST_STRUCT; DWORD tt = ((TEST_STRUCT *)0)->c;    // mov eax,dword ptr ds:[00000008h] 위의 구문과 아래의 구문을 비교해 보자. 차이즌 앰퍼센드이다(&) DWORD tt = (DWORD)( & ((TEST_STRUCT *)0)->c ); // dword ptr [ebp-18h],8 즉 구조체 레이아웃에서 c의 옵셋을 의미한다.

[WinDbg] Critical error detected c0000374

HeapFree()를 수행할때 제목 그대로 에러를 표시하면서 프로그램이 종료가 된다. 이유가? HeapFree(1,2,3); <- 3번의 UsertPtr를 가리키고 있는데 이를 WINDBG로 확인해 보면 HEAP_ENTRY Size Prev Flags UserPtr UserSize - state 위와 같이 나오는데 WIN7기준 UserSize +24byte = Result Result/8의 값이 Size 에 명시가 되어 있어야 하는데 이 값이 원래의 값보다 적다. 고로 메모리를 넘어서서(오버플로우) 쓰는 부분이 어디엔가 있다. 이거를 찾아야 한다. WINDBG하에서 모니터링해볼수도 있고 코드를 눈을 크게 뜨고 볼수도 있고. 알아서..

[WinDbg] Stack Overrun

/GS 플래그가 지정되었을때 함수 호출부와 함수 끝부분에서 쿠키값을 비교. 비교결과 틀리게 되면 해당 함수부의 지역변수의 영역을 넘어섰음을 의미한다. 따라서 특정 함수의 마지막부분을 가리키면서 해당 오류코드를 뱉어낸다면 함수 부분에서 지역변수를 넘어설 수 있는 지점을 하나씩 주석처리해 가면서 찾는다. 좋은 습관은 방어코딩이다. 나의 경우는 다음과 같은 것이었다. filepath[512]; wcscpy( filepath, objectName.Buffer, objectName.Length / 2 ); <-- objectName.Length/2가 항상 512보다 작다는 것을 보장할 수 있나? 보장할 수 없기 때문에 최악의 경우 넘어서지 않도록 조치를 해줘야 한다. wcscpy_s류 같은 것들을 쓰자 gflags.exe를 이용한 디버깅 방법   일단 OS한테 특정 process에 대해서 user stack trace을 설정해 줘야 한다. 두가지 방법이 있는데 첫째는) gflags.exe를 이용하는 거고 둘째는) 커맨드 창에서 gflags.exe /i TestProgram.exe +ust 입력 결국, gflags.exe가 위의 명령의 결과로 다음의 레지스트리에 키값을 생성해 준다. HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution 키값 TestProgram.exe GlobalFlag RGB_SZ 0x1000 위처럼 OS flag를 설정한 후에 process 를 시작해야 하는 거고 이후에 windbg를 기동한 후에 해당 process 를 attach 한다. 테스트 프로그램1 ) Heap Block을 넘어선 Free --------------------------------------- char* p1 = (char*)malloc( 0x10 ); char* p2 = (char*)mall...

[WinAPI] 모달리스 다이얼로그 설명

이미지
출처 : http://www.winprog.org/tutorial/modeless_dialogs.html Now we take a look at CreateDialog() , DialogBox() 's sister function. The difference is that while DialogBox() implements it's own message loop and does not return untill the dialog is closed, CreateDialog() acts more like a window created with CreateWindowEx() in that it returns immediately and depends on your message loop to pump the messages as it does for your main window. This is termed Modeless , whereas DialogBox() creates Modal dialogs. You can create the dialog resource just like you did for the last dialog example, you might also want to set the "Tool window" extended style to give it's title bar the typical smaller caption of toolbars. The dialog resource I created follows: IDD_TOOLBAR DIALOGEX 0, 0, 98, 52 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION EXSTYLE WS_EX_TOOLWINDOW CAPTION "My Dialog Toolbar" FONT 8, "MS Sans Serif" BEGIN PUSHBUTTON "...

[WinDbg] Debugging a stack overflow

참조 : http://msdn.microsoft.com/en-us/library/windows/hardware/ff540620(v=vs.85).aspx Debugging a Stack Overflow 5 out of 11 rated this helpful - Rate this topic A stack overflow is an error that user-mode threads can encounter. There are three possible causes for this error: A thread uses the entire stack reserved for it. This is often caused by infinite recursion. A thread cannot extend the stack because the page file is maxed out, and therefore no additional pages can be committed to extend the stack. A thread cannot extend the stack because the system is within the brief period used to extend the page file. When a function running on a thread allocates local variables, the variables are put on the thread's call stack. The amount of stack space required by the function could be as large as the sum of the sizes of all the local variables. However, the compiler usually performs optimizations that reduce the stack space required by a function. For example, if two...

[WinDbg] DbgPrint VISTA 출력되지 않을때

출처 : http://oasess.tistory.com/entry/VISTA-에서-Debug-메세지 -출력 요약하면 코드를 수정하던가 DbgPrintEx( DPFLTR_DEFAULT_ID, DPFLTR_INFO_LEVEL, "XXX" ) Windbg 환경하에서(커널디버깅) 당연히 매번 입력해줘야 되는 거고 ed Kd_DEFAULT_MASK 8 : INFO_LEVEL인 경우 ed Kd_DEFAULT_MASK 0xF : ERROR_LEVEL인 경우 ed Kd_DEFAULT_MASK 0 : 끌 경우 아님 레지스트리에 기록을 해준다.(재부팅 필요) HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\ Debug Print Filter REG_DWORD 0xF

[WinAPI] allocation granularity란?

더 자세한 사항은 아래에서 참조 http://luto.tistory.com/28 region들의 집합이 윈도우즈 메모리 1개의 region 은 64kb 프로그램에서 메모리를 할당받을때 사용되는 단위가 allocation granularity인데, 크기는 64kb 1개의 page 는 메모리 할당의 최소의 단위로 4kb (만약 프로그램에서 10kb의 메모리 공간을 할당받으려 하면, x86기반에서는 4kb의 배수인 12kb를 할당받게 된다) SYSTEM_INFO si; GetSystemInfo(&si); si.dwPageSize = 4096 si.lpMinimumApplicationAddress = 0x00010000 si.lpMaxkimApplicationAddress = 0x7ffeffff si.dwAllocationGranularity = 65536 PageTable 에는 페이지가 램에 존재하는지 페이징파일에 존재하는지에 대한 정보를 갖고있다 가상메모리 공간을 확보하거나 커밋하기 위해 다음의 함수를 쓴다. VirtualAlloc (  LPVOiD lpAddress,  DWORD dwSize,  DWORD flAllocationType,  DWORD flProtect ); lpAddress : 시스템이 자동으로 빈공간을 정하도록 할때에는 NULL, 특정주소를 넘겨줄땐 반드시 UserArea 범위내의 주소. 주의점으로 이 주소값을 할당세밀도(allocation grarularity)의 단위에 맞춰야 한다. (64kb+1024byte)의 영역을 할당하게 되면 시스템은 이를 내림하여 (64kb)의 주소부터 영역을 할당하게 된다. dwSize : 확보하고 싶은 주소의 크기를 바이트 단위로. 영역의 크기는 반드시 시스템 페이지의 크기의 배수여야 한다. flAllocatioType : 확보할것인지, 커밋할것인지를 나타냄. 차곡차곡 순서대로 영역이 확보될것이라는 보장은 없다. flProtect : 해당영역에 할당할 보호 ...

[Code Snip] 서비스에서 관리자권한으로 프로세스 실행

lancer wrote: Now I need to create a process with administrator privilege from a service on Vista. By adjust the Integrity Level of the user token, the process becomes HIGH. However it still has no administrator privileges. I did it as the following: 1.Get the session if of the active console user (WTSGetActiveConsoleSessionId) 2.Get the user's token (WTSQueryUserToken) 3.duplicate the token ((DuplicateTokenEx) 4.Set the integrity level to be High. (SetTokenInformation) Between steps 2 and 3, call GetTokenInformation() with TokenLinkedToken to get the linked (elevated) token, and remove step 4. The code might be similar to: TOKEN_LINKED_TOKEN linkedToken = {0}; /* The token is not elevated, we will build an elevated token for the */ /* user. */ dwSize = sizeof linkedToken; /* Get the linked token, which is the elevated version of the current */ /* token. */ if (GetTokenInformation(hToken, TokenLinkedToken, &linkedToken, dwSize, &dwSize)) { /* The linked token is not a p...

[WinAPI] DllMain() 주의점 그리고 DONT_RESOLVE_DLL_REFERENCES

출처 : http://isecurity-textcube.blogspot.com/2010/04/dll%EC%9D%98-%EA%B3%A0%EA%B8%89%EA%B8%B0%EB%B2%95.html   DONT_RESOLVE_DLL_REFERENCES     이 플래그는 LoadLibraryEx함수를 호출하는 프로세스의 주소공간에 매핑할 것을 지정한다. 보통 dll이 프로세스의 주소공간에 매핑되면 시스템은 일반적으로 DllMain()이라고 불리는 특수한 함수를 호출하여 dll을 초기화하도록 한다.  DONT_RESOLVE_DLL_REFERENCES 플래그를 사용하면 시스템은 DLL파일이미지가 매핑되는 작업까지만 수행하고 DllMain()함수는 호출하지 않는다 . 또한 DLL 파일은 다른 DLL이 포함하고 있는 함수들을 임포트하기도 하는데, 시스템이 DLL을 프로세스 주소공간에 매핑할 때 다른 DLL이 필요한지를 확인하여 자동적으로 이러한 dll들을 로드해준다. 이 플래그를 사용하면 매핑할 DLL이 필요로 하는 추가적인 DLL을 프로세스의 주소공간에 자동으로 로드하지 않는다 ( DONT_RESOLVE_DLL_REFERENCES 가 지정이 되면 매핑만 하고 DllMain() 호출하지 않고, 해당 DLL과 연관되어 있는 다른 DLL들을 자동으로 로드해주지 않는 특성을 갖고 있다 ) DLL이 익스포트하고 있는 함수들은 내부적인 자료구조가 완전히 초기화되고 추가적으로 필요로 하는 DLL파일들이 로드되기 전까지는 호출될 수 없다. 따라서 가능하면 이플래그는 사용하지 않는 것이 좋다. 잘못만들어진 플래그라고 한다(레이몬드첸의 블로그에서 확인, http://blogs.msdn.com/oldnewthing/archive/2005/02/14/372266.aspx )로 부터 "LoadLibraryEx(DONT_RESOLVE_DLL_REFERENCES)는 완전히 잘못만들어졌다"는 글을 살펴보기 바란다   LOAD_L...

[WinDbg] Heap Corrupt - Overrun

힙오버런 의 경우는 초기화안된 상태의 결과와는 틀릴 수 있다. 그냥 실행하는 경우에 문제가 없다고 나올 수 있는 것이다. 경험적으로 초기화안된 상태의 경우("Heap 손상 - 초기화안된 상황" 참조) 디버거에서 실행하는 경우 : 채움패턴으로 인해서 바로 AV를 발생시켜줌 그냥 실행하는 경우 : 보통 프로세스 종료시 문제 발생 힙오버런의 경우 디버거에서 실행하는 경우 : "Heap block at 00152E50 modified at 00152E6C past requested size of 14" 왼쪽과 같은 메시지를 뿌려준다. 아래 참조 보통 이 경우를 확인하는 첫번째 방법으로는 세그먼트가 정상적으로 보존되어 있는지를 확인해 보는것이 먼저 해야 할 순서이다. !heap 명령어를 쓰거나 Segments 멤버의 링크되어 있는 노드를 순서적으로 접근을 해 본다. 이렇게 해 보면 보통의 경우는 가장 마지막 노드의 메타데이터가 깨져 있는 것을 알 수가 있다. 그냥 실행하는 경우 : 이상없이 종료됨 00152e50  06 00 07 00 7d 07 1c 00 - 30 00 31 00 32 00 33 00  ....}...0.1.2.3. 00152e60  34 00 35 00 36 00 37 00-38 00 39 00 30 00 31 00   4.5.6.7.8.9.0.1. 00152e70  32 00 33 00 34 00 35 00-36 00 37 00 38 00 39 00  2.3.4.5.6.7.8.9. 파란색 : 메타데이터(8바이트) 빨간색 : 할당된 유저 영역(20바이트) 녹색 : 후위바이트영역(이 부분을 넘어서 사용하고 있어서 힙손상을 일으키고 있다.) 일반페이지힙을 설정한 후에 그냥 실행하는 경우에는 어플리케이션 베리파이어의 영향으로 손상지점을 좀더 쉽게 파악할 수가 있다. gflags -p /enable "이미지 풀패스" 엔터 일반페이지힙과 비교해서 완전페이지힙은 손상시점의 확인을 나중에...

[Code Snip] shut down my computer

It is very interesting to write your own application to Shut Down , Restart or Log Off the system. right? Its not a big task. Very simple to make it. Simply use the Win32 API ExitWindowsEx to do this. It sends the WM_QUERYENDSESSION to all applications to determine if they can be terminated. BOOL ExitWindowsEx(UINT uFlags, DWORD dwReason) uFlags tells what to do. Different values possible are. 1) EWX_LOGOFF 2) EWX_POWEROFF 3) EWX_REBOOT 4) EWX_RESTARTAPPS 5) EWX_SHUTDOWN dwReason � indicates the reason for initiating the shutdown. void ToShutdownMySystem() {    HANDLE hToken;    TOKEN_PRIVILEGES tkp;      // Get a token for this process.      if (!OpenProcessToken(GetCurrentProcess(),       TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))       AfxMessageBox("Failed to get the token for this process");      // Get the LUID for the shutdown privilege. ...

[WinAPI] Tls 사용하는 방법 #1

#include "stdafx.h" #include <windows.h> #include <stdio.h>   #define THREADCOUNT 4 DWORD dwTlsIndex;   VOID ErrorExit(LPSTR);   VOID CommonFunc(VOID) {    LPVOID lpvData;   // Retrieve a data pointer for the current thread.      lpvData = TlsGetValue(dwTlsIndex);    if ((lpvData == 0) && (GetLastError() != ERROR_SUCCESS))       ErrorExit("TlsGetValue error");   // Use the data stored for the current thread.      printf("common: thread %d: lpvData=%lx\n",       GetCurrentThreadId(), lpvData);      Sleep(5000); }   DWORD WINAPI ThreadFunc(VOID) {    LPVOID lpvData;   // Initialize the TLS index for this thread.      lpvData = (LPVOID) LocalAlloc(LPTR, 256);    if (! TlsSetValue(dwTlsIn...