0x00 前言
最近學習了Stuart@ukstufus的文章《Persistence Architecture Matters》,恰巧解決了我之前遇到過的一個問題,理清了文件和注冊表重定向中需要注意的細節
大家在學習的過程中難免也會碰到,所以在此分享一下。
《Persistence Architecture Matters》的鏈接:
https://labs.mwrinfosecurity.com/blog/persistence-architecture-matters/
0x01 消失的注冊表鍵值
OS:Win8x64
開發環境:VS2008
1、編寫程序寫入注冊表
代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include <atlbase.h>
int
main(
int
argc,
char
*argv[])
{
LPCTSTR
lpSubKey =
"Software\\Microsoft\\Windows\\CurrentVersion\\Run"
;
HKEY
hKey;
DWORD
dwDisposition = REG_OPENED_EXISTING_KEY;
LONG
lRet = ::RegCreateKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition);
if
(ERROR_SUCCESS != lRet)
{
return
0;
}
char
szModuleName[MAX_PATH] = { 0 };
::GetModuleFileNameA(NULL, szModuleName, MAX_PATH);
lRet = ::RegSetValueEx(hKey,
"test"
, NULL, REG_SZ, (
BYTE
*)szModuleName,
strlen
(szModuleName) + 1);
if
(ERROR_SUCCESS != lRet)
printf
(
"RegSetValueEx error!\n"
);
else
printf
(
"[+] RegSetValueEx Success!\n"
);
::RegCloseKey(hKey);
return
0;
}
|
編譯平台設置為Win32
以管理員權限運行后會向HKLM\Software\Microsoft\Windows\CurrentVersion\Run
寫入鍵值test
如圖
2、獲取寫入的鍵值
編寫批處理文件來獲得寫入的結果
批處理內容如下:
1
|
REG query
"HKLM\Software\Microsoft\Windows\CurrentVersion\Run"
/v
"test"
>>result.txt
|
在本地右鍵直接執行批處理文件
可是,批處理執行后無法輸出寫入的鍵值
0x02 消失的文件
1、編寫程序寫入文件
代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
#include <stdio.h>
void
main()
{
char
*temp=
"test"
;
FILE
* fp;
fp=
fopen
(
"c:\\windows\\system32\\test.txt"
,
"a+"
);
if
(fp==0)
return
;
fwrite
(temp,
strlen
(temp),1,fp);
printf
(
"[+] Write Success!\n"
);
fclose
(fp);
}
|
編譯平台設置為Win32
以管理員權限運行后會向c:\windows\system32\
寫入文件test.txt
如圖
2、獲取寫入的文件
批處理內容如下:
1
|
dir
c:\windows\system32\
test
.txt >>result.txt
|
在本地右鍵直接執行批處理文件
同樣,批處理無法輸出寫入的文件內容
0x03 原因分析
1、重定向
自xp系統開始,64位的系統引入了新技術:
文件重定向和注冊表重定向
這個技術是為了在64位系統下將32位程序和64程序分離開
在64位平台上運行32位程序的模擬器被稱為WOW64
WOW64全稱為"Windows 32 on Windows 64"
2、注冊表重定向
在X64系統里面,一些特殊的注冊表鍵會被分為2個獨立的部分
(1)32位程序對注冊表某些位置的操作存在重定向
比如對HKLM/Software訪問,會被WOW64重定向至HKLM/Software/Wow6432Node
具體存在重定向的注冊表位置可參考如下鏈接:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa384253(v=vs.85).aspx
(2)64位程序對注冊表的操作不存在重定向
(3)補充
HKLM/Software/Wow6432Node下保存的均為32位程序的注冊表信息
如果在HKLM\Software\Wow6432Node\Microsoft\CurrentVersion\Run
添加啟動項來運行dll,系統默認會執行32位的rundll32.exe(路徑為:c:\windows\SysWOW64\rundll32.exe)來加載dll,加載的dll必須是32位(如果是64位會出錯)
當然,如果在HKLM\Software\Microsoft\Windows\CurrentVersion\Run
添加啟動項來運行dll,則默認為64位rundll32.exe,加載64位dll文件
3、文件重定向
同樣,文件系統也存在2個獨立的部分
(1)32位程序對%systemroot%/system32
的操作存在重定向
32位文件會被重定向到%systemroot%/SysWOW64
(2)64位程序對文件操作不存在重定向
(3)補充
%systemroot%/SysWOW64下的都為32位程序,在里面可以找到32位的cmd、calc等
基於以上的分析,整理出了如下操作注冊表鍵值和文件系統的方法
0x04 找回注冊表鍵值
解決思路:
32位程序寫注冊表的操作會被重定向到HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run
而在本地執行批處理默認會調用64位的程序,不會被重定向,查詢的位置為HKLM\Software\Microsoft\Windows\CurrentVersion\Run
解決方法:
1、修改調用的api參數,跳過重定向,使32位程序去訪問64位的注冊表
在調用函數RegCreateKeyEx創建注冊表項時,對其第六個參數REGSAM samDesired設置中添加參數KEY_WOW64_64KEY
即KEY_ALL_ACCES
改為KEY_ALL_ACCESS | KEY_WOW64_64KEY
這樣就會跳過重定向,最終寫入的位置為HKLM\Software\Microsoft\Windows\CurrentVersion\Run
修改后的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include "stdafx.h"
#include <atlbase.h>
int
main(
int
argc,
char
*argv[])
{
LPCTSTR
lpSubKey =
"Software\\Microsoft\\Windows\\CurrentVersion\\Run"
;
HKEY
hKey;
DWORD
dwDisposition = REG_OPENED_EXISTING_KEY;
LONG
lRet = ::RegCreateKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, NULL, NULL, REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, &hKey, &dwDisposition);
if
(ERROR_SUCCESS != lRet)
{
printf
(
"RegCreateKeyEx error!\n"
);
return
0;
}
char
szModuleName[MAX_PATH] = { 0 };
::GetModuleFileNameA(NULL, szModuleName, MAX_PATH);
lRet = ::RegSetValueEx(hKey,
"test"
, NULL, REG_SZ, (
BYTE
*)szModuleName,
strlen
(szModuleName) + 1);
if
(ERROR_SUCCESS != lRet)
printf
(
"RegSetValueEx error!\n"
);
else
printf
(
"[+] RegSetValueEx Success!\n"
);
::RegCloseKey(hKey);
return
0;
}
|
再次執行批處理
1
|
REG query
"HKLM\Software\Microsoft\Windows\CurrentVersion\Run"
/v
"test"
>>result.txt
|
成功獲得鍵值
如圖
注:
也可結合使用Wow64DisableWow64FsRedirection
和Wow64RevertWow64FsRedirection
關閉和開啟重定向,以此來跳過重定向,寫入64位的注冊表
2、修改批處理,查詢重定向后的注冊表鍵值(驗證結論用)
不修改原程序,默認讓其寫入HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run
修改批處理文件查詢重定向后的注冊表鍵值,代碼為:
1
|
REG query
"HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run"
/v
"test"
|
在本地右鍵執行后可成功獲得鍵值
注:
實際測試的過程中很少能夠在本地右鍵執行批處理,所以該方法僅作驗證思路
通常情況下,32位的程序執行批處理文件也會存在重定向的問題。
0x05 找回文件
解決思路:
同樣,32位程序寫入c:\windows\system32\
的操作會被重定向到c:\windows\SysWOW64\
32位程序如果需要訪問真正的c:\windows\system32\
,可訪問c:\windows\Sysnative\
1、修改批處理
32位程序生成的文件實際位置為C:\Windows\SysWOW64\test.txt
所以批處理對應的內容如下:
1
|
dir
C:\Windows\SysWOW64\
test
.txt >>result.txt
|
2、補充
(1)之前遇到過的一個問題:
在測試Security Support Provider的時候就存在這個問題:
http://drops.wooyun.org/tips/12518
使用32位的程序將mimikatz.dll上傳至域控(Server2008x64)的c:\windows\system32\下
由於重定向的緣故mimikatz.dll實際的上傳位置為C:\Windows\SysWOW64,因此導致測試失敗
解決方法:
- 文件的復制路徑改為c:\windows\Sysnative
- 換用批處理實現復制功能,不會存在重定向問題
(2)可供測試32位和64位程序區別的小方法:
32位cmd:
1
|
C:\Windows\SysWOW64\cmd.exe
|
64位cmd:
1
|
c:\windows\system32\cmd.exe
|
分別執行寫注冊表和寫文件的操作,重定向的細節顯而易見
寫注冊表:
1
|
reg add
"HKLM\Software\Microsoft\Windows\CurrentVersion\Run"
/v
"test"
|
查詢注冊表:
1
2
|
REG query
"HKLM\Software\Microsoft\Windows\CurrentVersion\Run"
/v
"test"
REG query
"HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run"
/v
"test"
|
寫文件:
1
|
copy
test
.txt c:\windows\system32\
test
.txt
|
查找文件:
1
2
3
|
dir
c:\windows\system32\
test
.txt
dir
C:\Windows\SysWOW64\
test
.txt
dir
C:\Windows\Sysnative\
test
.txt
|
0x06 小結
32位程序在64系統下執行的時候,如果有對注冊表和文件的操作,重定向的細節必須考慮。
對注冊表操作:
訪問HKLM\Software\
的實際路徑為HKLM\Software\Wow6432Node\
對文件操作:
訪問c:\windows\Sysnative\
的實際路徑為 c:\windows\system32\
訪問c:\windows\system32\
的實際路徑為 c:\windows\SysWOW64\
引用Stuart@ukstufus文章中的兩幅圖,能夠幫助大家更清晰的認識其中的細節。
感謝Stuart@ukstufus的分享。解決了我的問題,也讓我有了更清楚的認識。
更多學習資料:
- https://msdn.microsoft.com/en-us/library/windows/desktop/aa384232(v=vs.85).aspx
- https://msdn.microsoft.com/en-us/library/windows/desktop/aa384187(v=vs.85).aspx
本文由三好學生原創並首發於烏雲drops,轉載請注明
http://drops.wooyun.org/tips/14831