위 표에 1행은 (#) 넣어서 링크를 만들었네. 대괄호로 문자열 감싸고 그 옆에 소괄호로 링크 넣으면 첨부된다.
아래는 행마다 정렬이 다르니까 참고
+) 표 위아래 모두 한 줄씩 띄워야 한다.
Header1
Header2
Header3
cell1
cell2
cell3
cell4
cell5
cell6
cell1
cell2
cell3
cell4
cell5
cell6
Foot1
Foot2
Foot3
Definition Lists
Definition List Title
Definition list division.
본문 아랫줄에 : 넣고 작성하면 들여쓰기가 된다.
Unordered Lists (Nested)
List item one
List item two
List item three
List item four
리스트는 그냥 참고하자.
Ordered List (Nested)
List item one
a. List item one
1. List item one
2. List item two
3. List item three
4. List item four
b. List item two
c. List item three
d. List item four
word-wrap: break-word;strikeout textitalicize inserted keyboard textbold text H2O E = MC2
문자 스타일? 효과를 넣을 수 있다.
코드 작성
.post-title {
margin: 0 0 5px;
font-weight: bold;
font-size: 38px;
line-height: 1.2;
and here's a line of some really, really, really, really long text, just to see how the PRE element handles it and to find out how it overflows;
}
< pre>로도 할 수 있는데 맠다 형식으로 작성하는 게 편한 거 같다. 아래 유튜브 추가하는 코드 첨부하면서 맠다 형식 넣었다.
Images
이미지 임베드 중요하지.. 근데 생각해보니까 이거 어느 폴더에 넣지? _screenshots에 넣어야 하나
유튜브 첨부
<!-- responsive iframe. The framesize reduces proportionately when viewing in mobile --><divclass="video-container"><iframeclass="embed-responsive-item"src="..."></iframe></div>
Howdy! This is an example blog post that shows several types of HTML content supported in this theme.
맠다 형식과 Html 스타일 비교
To bold text, use <strong>.
To italicize text, use <em>.
Abbreviations, like HTML should use <abbr>, with an optional title attribute for the full phrase.
Citations, like — Mark otto, should use <cite>.
Deleted text should use <del> and inserted text should use <ins>.
Superscript text uses <sup> and subscript text uses <sub>.
여러 코드 임베드 비교
// Example can be run directly in your JavaScript console// Create a function that takes two arguments and returns the sum of those argumentsvaradder=newFunction("a","b","return a + b");// Call the functionadder(2,6);// > 8
from Crypto.Util.number import *
from flag import flag
p = bytes_to_long(flag)
assert isPrime(p)
q = getPrime(256)
d = pow(65537, -1, (p - 1) * (q - 1))
print(d)
# 22800184635336356769510601710348610828272762269559262549105379768650621669527077640437441133467920490241918976205665073
p는 소수
어떤 거 구해서 마지막에 long_to_bytes하면 그게 flag
de=1(mod pq)
이걸 좀 풀어서 쓰면
de-1=n(q-1)(p-1)이다(n은 자연수)
factorint로 소인수분해 하면 아래와 같다.
일단 가장 큰 수는 256비트이기 때문에 조합할 경우의 수가 많지 않다.
그래서 직접 prime인지 체크해봤더니 모두 false -> n에 들어가는 인수이다.
ai의 도움을 받아 가장 큰 인수 빼고 코드를 짜보면…
from itertools import combinations
from sympy import isprime
def find_valid_p(n_factors):
valid_p = set()
factors = []
for base, exp in n_factors.items():
factors.extend([base] * exp)
for r in range(1, len(factors) + 1):
for combo in combinations(factors, r):
p = 1
for factor in combo:
p *= factor
if p % 2 == 0 and isprime(p + 1):
valid_p.add(p)
return sorted(valid_p)
n_factors = {
2: 3, 3: 1, 5: 2, 37: 1, 1117: 1, 4029461: 1,
1403014978139: 1, 284368748316481195117: 1
}
valid_p = find_valid_p(n_factors)
print(valid_p)
가능한 인수들을 모두 출력해준다.
위에 넣고 p-1을 p로 바꾼 후 long_to_bytes하여 경우의 수를 모두 출력해주면, DH 플래그가 나온다.
주로 쓰고 기초적인 함수들을 미리 만들어서 모아둔 것을 라이브러리라고 한다. DLL은 Dynamic Link Library를 뜻하는데, 해당 라이브러리를 사용할 때만 파일을 다운하여 기능을 호출한다. 정적 링크는 함수를 복사해서 붙여넣기라고 생각하고 동적 링크는 잠깐 위치를 옮겨서 호출받았다가 원함수로 돌아오는 거라고 이해했다. DLL은 메모리에 로드되면 DllMain을 실행한다.
DllMain()은 진입점 함수이다. 진입점 함수란 프로그램이 처음 시작될 때 호출되는 함수이다. DllMain 함수는 세 개의 인자를 가진다. hModule, fdwReason, IpReserved이다. hModule은 DLL 파일 이미지가 매핑된 가상 메모리 주소값이다.
DLL 인젝션이란 말 그대로 특정 프로세스에 DLL을 삽입하는 것이다. DLL을 프로세스에 삽입하면 DllMain이 실행되면서 이때 목적에 따라 코드를 넣어 프로그램이 진행될 수 있다.
DLL 인젝션 활용 예시
DLL 인젝션은 다음과 같은 경우에서 활용할 수 있다.
기능 개선 및 버그 패치: 프로그램의 소스 코드가 없는 등 수정할 수 없는 경우에 DLL 인젝션을 이용해서 새로운 기능을 추가하거나 코드, 데이터를 수정할 수 있다.
메시지 후킹: 등록된 후킹 DLL을 OS에서 직접 인젝션시켜준다.(메시지 후킹에 관해서는 아래서 자세히 서술했다.)
API 후킹: API 후킹이란 Win32 API가 호출될 때 중간에서 이를 가로채서 제어권을 얻어내는 것이다. Win32 API는 Windows에서 제공하는 API인데 원래 Windows OS는 프로그램이 시스템 자원에 접근할 수 없다. 하지만 시스템 접근이 필요할 때 이 API를 이용해서 시스템 커널에 접근을 요청한다. 후킹 함수를 DLL 형태로 만들고 인젝션하여 활용할 수 있다.
기타 응용 프로그램: PC 사용자를 감시/관리 하는 프로그램 목적으로도 쓰인다. 실행 차단, 유해사이트 접속 차단, 모니터링 프로그램 등이 있다.
악성코드: 정상적인 프로세스에 들어가서 백도어 포트를 열고 외부에서 접속하거나, 키로깅 기능 등으로 개인 정보를 훔치는 등 사용하고 있다.
DLL 인젝션 - 원격 스레드 생성 이용
다음은 블로그에서 발췌한 소스코드이다. 먼저 주석까지 그대로 작성했다. 인젝션 과정에 대해서는 코드 아래서 설명했고 그 외 세부적으로 이해가 안 되는 함수 등은 용어 정리 또는 소스 코드 안에 ///를 기입하고 작성하였다.
Myhack.cpp
// Myhack.cpp
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
BOOL Go_Injection(DWORD dwPID, LPCSTR DllPath) {
//프로세스 핸들
HANDLE hProcess = NULL;
//스레드 핸들
HANDLE hThread = NULL;
//모듈 핸들
HMODULE hMod = NULL;
//DLL 경로를 기록한 메모리 주소를 넣을 포인터변수
LPVOID pRemoteBuf = NULL;
//스레드 시작 루틴 함수주소를 저장할 변수
LPTHREAD_START_ROUTINE pThreadProc;
//인젝션 할 프로세스 제어권 얻기
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
printf(" [+] 프로세스의 핸들(hProcess) : %d\n", hProcess);
//DLL경로의 길이 얻기
DWORD dwBufSize = (DWORD)(strlen(DllPath) + 1);
printf(" [+] DLL의 길이 : %d byte\n", dwBufSize);
//인젝션 할 DLL 경로를 해당 프로세스에 기록
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READONLY);
WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)DllPath, dwBufSize, NULL);
printf(" [+] 인젝션할 프로세스 내 할당받은 메모리주소 : 0x%p\n", pRemoteBuf);
printf(" [+] 할당받은 주소에 작성할 DLL의 경로 : %s\n", DllPath);
//write한 DLL을 프로세스에서 로드하기 위한 작업
hMod = GetModuleHandleA("kernel32.dll");
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryA");
printf(" [+] 스레드의 시작주소(LoadLibrary) : 0x%p\n", pThreadProc);
//write한 DLL을 인젝션할 프로세스에 스레드 생성 후 스레드의 시작주소로
//LoadLibraryA를 지정
hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
printf(" [+] 인젝션한 프로세스에서 실행한 스레드 식별자 : %d\n", hThread);
//스레드가 실행될 때까지 무한정 대기
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
return 1;
}
int main(int argc, CHAR *argv[]) {
if (argc != 3) {
printf(" [-] Usage : %s [Process_Name] [DLL_Path] \n", argv[0]);
//argv[0]=인젝션시킬프로그램, argv[1]=인젝션할 프로세스 이름, argv[2]=dll경로
return 0;
}
//PID=-1
DWORD dwPID = 0xFFFFFFFF;
HWND hWnd = FindWindowA(NULL, argv[1]);
printf(" [+] 프로세스의 창 번호(hWnd) : %d\n", dwPID);
//Go_Injection 함수의 인자로 PID와 DLL의 경로를 넘겨줌
//Go_Injection함수 정상동작 시 TRUE 반환
BOOL flag = Go_Injection(dwPID, argv[2]);
return 0;
}
인젝션을 하기 위해 핸들을 얻어야 한다.
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
OpenProcess는 PID를 통해 핸들을 얻어올 때 사용한다. 위 코드를 해석하자면 PROCESS_ALL_ACCESS(접근권한)의 myhack.dll(dwPID) 핸들을 구한다. hProcess를 이용하여 제어할 수 있다.
VirtualAllocEx로 대상 프로세스의 메모리 공간 확보하기:
DLL 경로를 작성하기 위해 버퍼*를 할당해줘야 한다. 이때 절대경로의 문자열 길이만큼 할당해줘야 한다.
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READONLY);
dwBufSIze는 경로 문자열 길이(NULL 포함)이다. VirtualAllocEx는 가상 주소 공간 내에서 메모리 상태를 변경, 할당, 해제하는 함수이다. VirtualAllocEx()의 리턴값은 할당된 버퍼의 주소이다.
WriteProcessMemory로 대상 프로세스의 메모리에 Injection 할 DLL의 경로 입력:
이후 다음을 이용하여 절대경로를 작성해준다.
WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)DllPath, dwBufSize, NULL);
위 코드를 그대로 해석하면 hProcess 권한을 가지고 pRemoteBuf에 DllPath(DLL 경로 문자열)을 써준다는 뜻이다.
LoadLibrary API 주소 구하기 (GetModuleHandle, GetProcAddress):
LoadLibaryW() API를 실행시켜 myhack.dll을 호출해야 하는데 LoadLibaryA는 kernel32.dll 안에 존재한다. 때문에 kernel32.dll에서 LoadlibraryA의 api 주소를 얻어낸다.
hMod = GetModuleHandleA(“kernel32.dll”);
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, “LoadLibraryA”);
pThreadProc = 프로세스 메모리 내의 LoadLibraryW() 주소
pRemoteBuf = 프로세스 메모리 내의 “C:\myhack.dll” 주소
CreateRemoteThread로 대상 프로세스의 Injection된 데이터 실행하기:
LoadLibrary()를 실행하면 DLL이 인젝션할 프로세스 메모리 안으로 삽입된다. 삽입되면 DllMain()이 호출되고 이는 공격자가 원하는 행위를 프로세스 내에서 실행할 수 있다는 뜻이다.
hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
CreateRemoteThread 함수는 가상 주소 공간에 실행되는 스레드를 생성한다. 프로세스 핸들을 가져야 한다. lpThreadAttributes는 하위 프로세스가 반환된 핸들을 상속할 수 있는지에 대한 여부를 나타내는 포인터이다. 본래 소스코드에서 NULL로 입력해줬으므로 스레드는 핸들을 상속할 수 없다. lpThreadId는 스레드 식별자를 수신하는 변수에 대한 포인터이다. 본 코드에서 NULL로 입력해줬으므로 스레드 식별자는 반환되지 않는다.
DLL injection – 레지스트리 이용
Windows 운영체제에서 제공하는 Applnit_DLLs와 LoadApplnit_DLLs라는 레지스트리* 항목이 있다.
Applnit_DLLs 항목에 인젝션을 원하는 DLL 경로 문자열을 쓰고 LoadApplnit_DLLs 항목의 값을 1로 변경한 후 재부팅하면, 모든 프로세스에 해당 DLL을 삽입한다.
Applnit_DLLs로 이동한다.
(경로:Mycomputer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows)
Applnit_DLLs의 값을 삽입할 DLL 경로로 변경한다.
LoadApplnit_DLLs의 값을 1로 입력한다.
재부팅한다.
프로세스 익스플로러에서 인젝션이 되었는지 확인한다.
DLL injection – 메시지 후킹
후킹은 정보를 염탐하거나 조작하는 행위를 말한다. Windows OS에서 키보드로 입력하고 마우스로 선택, 이동 등의 행위는 모두 이벤트이다. 이벤트가 발생할 때 OS는 이미 정의된 메시지를 프로그램으로 통보한다.
SetWindowsHookEx()를 이용하여 메시지 훅을 설치하면 운영체제에서 hook procedure을 담고 있는 DLL을 프로세스에게 강제로 삽입시킨다.
다음은 블로그에서 발췌한 소스코드이다. 먼저 주석까지 그대로 작성했다. 후킹 과정에 대해서는 코드 아래서 설명했고 그외 세부적으로 이해가 안 되는 함수 등은 용어 정리 또는 소스 코드 안에 ///를 기입하고 작성하였다.
GetProcAddress 함수는 특정 DLL에서 내보내기된 함수 또는 변수의 주소를 가져온다.
HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART);
HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP);
키보드 입력이 발생했을 때 현재 실행중 프로세스 이름과 “notepad.exe” 문자열과 비교하여 같다면 1을 반환하고 KeyboardProc() 함수를 종료시킨다. 이 부분이 메시지를 가로채서 없애는 동작이다.(후킹)
또 return CallNextHookEx(g_hHook, nCode, wParam, lParam); 명령을 실행하면 메시지는 다른 프로그램이나 다른 훅 함수로 전달된다.(후킹)
사용자로부터 키보드 입력 발생
OS는 키보드 입력이 발생한 해당 프로세스에 KeyHook.dll 인젝션
그 후 다시 키보드 입력이 발생하면 SetWindowsHookEx() 대신 KeyboardProc() 먼저 호출
용어 정리
백도어 포트: 공격자가 특정 컴퓨터에 침입하고 원할 때 재침입할 수 있게 만들어놓은 포트
키로깅: 키보드로 입력하는 정보를 중간에서 훅/후킹하는 해킹 도구
버퍼: 임시 저장 공간/ 가상 공간
레지스트리: 윈도우 시스템에서 사용하는 데이터베이스. 프로세스 종류, 주기억장치의 용량, 주변장치 정보 등 시스템 구성 정보가 담겨있다.
느낀 점
멘토님 피드백을 받고 이대로 공부 느낌을 살릴지, 칼럼적으로 파고들지 고민을 많이 했는데 일단 공부 목적을 살리기로 했다. 사실 인젝션에서 최신 동향 조사가 제대로 안됐고 프롬프트 인젝션은 내가 지향하는 해킹 기술 공부와는 거리가 멀어보였다. 그래서 그냥 다양한 인젝션을 알아보는 방향으로 정했다. 내가 궁금해서 찾는 경우가 많아서 조사도 실습도 즐겁게 진행할 수 있었지만, 내가 얼마나 서칭하냐에 따라 스터디 역량이 크게 바뀌는 것 같다.
이번 주제가 이미 정의되어 있는 함수에 대한 지식이 부족해서 공부가 어려웠다. 사실 DLL 인젝션이 잘 설명되어 있는 책이 하나인건지 찾는 국내 블로그마다 실습이 똑같았는데 그럼에도 모르는 부분이 많아서 이해하기까지 오래 걸렸고 이해못하고 넘어간 부분도 있는 거 같아 아쉽다. 또, 분량 조절을 못해서 생각보다 오래 걸렸다… 다음부턴 미리미리 시작해서 제시간에 제출해야겠다…
+) 3학년 되고 보니까 어째 이때보다 공부를 안 하는 느낌이다. 분발하자 ㅋㅎ
다음 뉴스 스터디 방향
Reflective Dll injection에 대해 찾아보고 오늘 찾은 DLL injection과 비교해볼 예정이다.
참고자료
DLL이란? (Dynamic Link Library) . (n.d.). https://goddaehee.tistory.com/185.