2018의 게시물 표시

네트워크 드라이브 마운트하기

기본적으로 WNetAddConnection2 를 사용하면 됨 인증관련 창이 뜰때 내 윈도우 핸들을 넘기고 싶으면 WNetAddConnection3 를 사용 주의점으로 WNet API를 호출하는 어플리케이션은 user logon에 대해서만 적용을 받기 때문에, 전역적으로 영향을 주려면 아래와 같이 해야 한다. If a service that runs as LocalSystem calls the WNetAddConnect2 fuction, then the mapped drive is visible to all user logon sessions. 예제) NETRESOURCE nr; memset(&nr, 0, sizeof(NETRESOURCE); nr.dwType = RESOURCETYPE_ANY; nr.lpRemoteName = m_csRemote; nr.lpProvider = NULL; dwRetVal = WNetAddConnection2(&nr, m_csUserName, m_csPassword, dwFlags); if( dwRetVal == NO_ERROR )   success else   fail username 입력, password 미입력시 67리턴(ERROR_BAD_NET_NAME) asd

NTLL!KiUserExceptionDispatcher(두번째 파라미터)

두번째 파라미터값에 대해서 조사를 해봐서 ContextFlags(1003f)이면 .cxr로 해당 컨텍스트로 이동해 볼수 있다 typedef struct _EXCEPTION_POINTERS {    PEXCEPTION_RECORD ExceptionRecord; // CPU 독립적인 정보    PCONTEXT ContextRecord; // CPU 의존적인 정보 } EXCEPTION_POINTERS , * PEXCEPTION_POINTERS ; 해당 정보는 다음의 2가지 경우에 저장이 될 수 있다. 1) exception filter 수행중 덤프 수집된 경우 2) exception filter 수행중 얻은 exception 정보를 저장한 경우(크래쉬 덤프) A) NTDLL!KiUserExceptionDispatcher ; 두번재 파라미터가 PCONTEXT B) kv 커맨드 ; CONTEXT @ 0f123456 C) msvcrt!__InternalCxxFrameHandler    - kpL 커맨드로 쉽게 볼 수 있다(첫번째 파라미터 Exception Record, 세번째 파라미터 Context Record) D) !dumpstack 또한 ContextRecord의 ContextFlags값은 i386 기준으로 1003f임 팁으로 s 커맨드로 범위내의 1003f 값을 갖는 경우를 찾기 위해서 다음과 같이도 할 수 있음 x86> s -d start_addr end_addr 1003f 약간 이상하기는 한데 ntdll!RtlDispatchException ntdll!KiUserExceptionDispatcher(2, 8, ...) 처럼 KiUser~() 두번째 파라미터가 CONTEXT를 가리키고 있지 않다면 위쪽에서(RtlDispatchException)을 검사해 봐라. 해당 위치에서는 i386인데도 1007f값을 가리킨다. 해당 위치로 CONTEXT를 위치시켜보면 정...

Kernel to User land(APC 인젝션)

커널모드에서 유저 프로세스로 코드를 인젝션시키는 두가지 방법이 존재 1) Queue user APC to alertable thread 타겟 프로세스의 어느 스레드가 alertable state인지를 알수 있는 코드가 필요하다. 각 스레드 ETHREAD 구조체를 검사해야 한다. thread가 alertable인지 설정되는 flag가 존재한다.  이 방법은 다소 신뢰할수 없고 MS가 해당 구조체를 무작위로 변경하기 쉽다는게 일반적 생각입니다. 2) Queue user APC to new thread 스레드가 시작하기 전에 스레드에 도달하는 방법이 필요합니다. 기본적으로 CreateThreadNotifyRoutine 등록함으로서 달성됩니다. 해당 콜백이 호출되면 두개의 시나리오중 하나가 발생될 수 있습니다. 2.1 스레드가 죽고 있음. 콜백이 죽는 스레드 컨텍스트에서 호출됨 2.2 스레드가 생성되고 있음. CNTR 콜백이 스레드 생성시 호출된것을 확인한 후에, 해당 스레드가 관심 프로세스에서 생성중인지를 알아보기 위해 몇가지 검사를 수행할 수 있다. CNTR에서 실행코드에서 기억할 중요한 사항으로는 각각의 CNTR이 끝나기전까지는 새로운 스레드가 만들어질 수 없다는 것이다. 만약 CNTR 코드가 실행하는데 1분이 걸린다면, 스레드 생성이 병목현상이 생긴다. 무엇을 하든지간에 그것이 빠르다는 것을 확인해라. 생성 스레드에 APC를 큐잉하기 위해, 커널코드가 신규 스레드에 ETHREAD 구조체를 갖을 필요가 있다. Win7에서 ETHREAD 구조체 핸들을 얻기 위해 PsLookupThreadByThreadId 호출할 수 있다. XP에서 코드검사가 실패해서 동작하지 않습니다. XP에서는 이 시점에 ETHREAD 구조체 얻기에 실패하는것으로 생각됩니다. 왜냐하면 오브젝트 리스트에 완전히 만들어지지 않기 때문에 다음으로, 2개의 파라미터를 갖는 KeStackAttachProcess 사용해 프로세스 컨텍스트에 붙일 필요가 있다....

SeDebugPrivilege 권한이 필요한 경우

High Integrity Level 프로세스에서 그보다 높은 Level 프로세스에 인젝션을 수행시도를 할때 SeDebugPrivilege 권한을 준다. 이 디버그 권한을 갖는다면 접근통제정책을 우회할 수 있다. 그러나 이 권한은 관리자 계정에만 주어진다. 즉 High Integrity Level인 경우에만 이 디버그 권한을 활성화시킬수 있다.

SetThreadContext Inject 테스트

void __declspec(naked) InjectFunction() {  __asm  {   PUSHAD    MOV EAX, 0xAAAAAAAA //eventually the address of LoadLibraryA    PUSH 0xBBBBBBBB //eventually the module name    call EAX    POPAD    //vc is pissy and requires us to emit the hardcoded jump    __emit 0xE9    __emit 0xCC    __emit 0xCC    __emit 0xCC    __emit 0xCC  } } void __declspec(naked) AfterFunction() { } void InjectDll( HANDLE hProc, HANDLE hThread, char *DllName ) {  //hold up  SuspendThread( hThread );  //get the thread context  CONTEXT ThreadContext;  ThreadContext.ContextFlags = CONTEXT_FULL;  GetThreadContext( hThread, &ThreadContext );  //copy the function to a tmp buffer  ULONG FunctionSize = (PBYTE)AfterFunction - (PBYTE)InjectFunction;  PBYTE LocalFunction = ...

static_cast와 reinterpret_cast 예제로 본 차이

#include "stdafx.h" #include <stdio.h> class shape{ private:     int a; public:     virtual void draw() { printf("share::draw() \n"); } }; class rect : public shape { private:     int b; public:     rect() { b = 30; }     void draw() { printf("rect::draw() \n"); }     void onlyRect() { printf("rect::onlyRect() \n"); } }; int _tmain(int argc, _TCHAR* argv[]) {     int arData[] = {1,2,3,4};     int * ptr = static_cast<int *>(arData);     char * pStr = "ABC";     ptr = static_cast<int *>(pStr); // error C2440: 'static_cast' : 'char *'에서 'int *'(으)로 변환할 수 없습니다.     rect rcTest;     shape * pShare = static_cast<shape *>(&rcTest);        // upcast     pShare->draw();     shape parent;     rect * pRect =...

ShellExecuteEx 예제

displayname 아닌 parsingname 얻어와서 호출하는 예제(IShellFolder 통해서 원하는 파일 찾는 부분 참고) https://docs.microsoft.com/ko-kr/windows/desktop/shell/launch #include <shlobj.h> #include <shlwapi.h> #include <objbase.h> main() {     LPITEMIDLIST pidlWinFiles = NULL;     LPITEMIDLIST pidlItems = NULL;     IShellFolder *psfWinFiles = NULL;     IShellFolder *psfDeskTop = NULL;     LPENUMIDLIST ppenum = NULL;     STRRET strDispName;     TCHAR pszParseName[MAX_PATH];     ULONG celtFetched;     SHELLEXECUTEINFO ShExecInfo;     HRESULT hr;     BOOL fBitmap = FALSE;     hr = SHGetFolderLocation(NULL, CSIDL_WINDOWS, NULL, NULL, &pidlWinFiles);     hr = SHGetDesktopFolder(&psfDeskTop);     hr = psfDeskTop->BindToObject(pidlWinFiles, NULL, IID_IShellFolder, (L...

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...