网页上的gameboy游戏模拟器
js里面的注释
//var romPath = "laoyanqiang.gb";
打开是张图片
拿gb模拟器打开rom/game.gb
内存c0a2处是Best Score 16位 改成ffff
结算界面变成了flag
图片隐写
:/mnt/d$ zsteg test.bmp --all --limit 2048
[?] 2 bytes of extra data after image end (IEND), offset = 0x269b0e
/usr/lib/ruby/2.5.0/open3.rb:199: warning: Insecure world writable dir /home/pwn/.cargo/bin in PATH, mode 040777
extradata:0 .. ["\x00" repeated 2 times]
imagedata .. text: ["\r" repeated 18 times]
b1,lsb,bY .. <wbStego size=120, ext="\x00\x8E\xEE", data="\x1Ef\xDE\x9E\xF6\xAE\xFA\xCE\x86\x9E"..., even=false>
b1,msb,bY .. text: "qwxf{you_say_chick_beautiful?}"
b2,lsb,bY .. text: "+UXr\"$!v"
b2,msb,bY .. text: "i2,C8&k0."
b3,lsb,bY .. text: "3`p:gyO1S"
b4,lsb,bY .. text: "\nme&Re'c"
b8,lsb,bY .. text: ["\r" repeated 18 times]
b1,lsb,bY,prime .. text: "riI?/1>^J"
b1,msb,bY,prime .. text: "UmlpFSkMwv"
b2,lsb,bY,prime .. text: "L#WEtj\"=}"
b2,msb,bY,prime .. text: "UjVe\"\n8;j"
b3,lsb,bY,prime .. text: "QE 9)\"IE\""
b3,msb,bY,prime .. text: "~~\"6QBK-\""
b4,lsb,bY,prime .. text: "RBRC44T#4$4D52C2"
b4,msb,bY,prime .. text: "(,\",,,,,"
b5,msb,bY,prime .. text: "ram9u!J1"
b6,lsb,bY,prime .. file: GeoSwath RDF
b2,r,lsb,xY .. text: "UUUUUU9VUUUUUUUUUUUUUUUUUUUUUU"
b2,g,lsb,xY .. text: "NUUUUUUUU^"
本题抄了一个模板:https://w3layouts.com/innovative-login-form-flat-responsive-widget-template/
注册登陆,发现文件上传,测试仅可上传图片,且只检测文件头。
随便找张图,在末尾添加shellcode,上传。
扫描得到//www.tar.gz
,解压得到源代码。
审计tp5\application\web\controller
下源码。
//Index.php
public function login_check(){
$profile=cookie('user');
if(!empty($profile)){
$this->profile=unserialize(base64_decode($profile));
$this->profile_db=db('user')->where("ID",intval($this->profile['ID']))->find();
if(array_diff($this->profile_db,$this->profile)==null){
return 1;
}else{
return 0;
}
}
}
存在反序列化。
寻找可利用的类。Register
中存在__destruct()
方法,调用this->checker->index()
。
Profile
类中存在__call()
方法
//Profile.php
public function upload_img(){
if($this->checker){
if(!$this->checker->login_check()){
$curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";
$this->redirect($curr_url,302);
exit();
}
}
if(!empty($_FILES)){
$this->filename_tmp=$_FILES['upload_file']['tmp_name'];
$this->filename=md5($_FILES['upload_file']['name']).".png";
$this->ext_check();
}
if($this->ext) {
if(getimagesize($this->filename_tmp)) {
@copy($this->filename_tmp, $this->filename);
@unlink($this->filename_tmp);
$this->img="../upload/$this->upload_menu/$this->filename";
$this->update_img();
}else{
$this->error('Forbidden type!', url('../index'));
}
}else{
$this->error('Unknow file type!', url('../index'));
}
}
public function __call($name, $arguments)
{
if($this->{$name}){
$this->{$this->{$name}}($arguments);
}
}
该文档针对爬虫系统设计目标中相应的场景给出技术方案
1、代码复用,功能模块化。可以支持上千个网站的数据爬取;
2、易扩展。爬虫框架易扩展,爬取规则、解析规则、入库规则易扩展,支持框架切换;
3、健壮性、可维护性。对数据爬取过程中的各种异常,例如:断网、反爬升级、爬“脏数据”等,需要实时的监控,以及给出准确的定位。异常处理以及降级措施需要完善;
4、后续扩展为分布式结构;
5、支持功能模块的易调整;
This task was categoried as pwn, but in fact it was RE and simple crypto. The hardest part of this task was to reverse engineer the binary.
main calls following functions:
000000000406950
is sha1 function from boost library. The proof is the string /usr/include/boost/uuid/sha1.hpp
.
0000000000406410
is also a cryptography function.
Let’s call it crypto_function
now, we will look at it closely later.
The pseudocode of main() function is below:
int main()
{
sha = boost_sha1(); //buffer of 16 bytes
if (strcmp(user_input(),"HELLO")) return 0;
bytes = read("/dev/urandom",16); //buffer of 16 bytes
print_bytes_hex(bytes);
bytes2 = read("/dev/urandom",16); //buffer of 16 bytes
print_bytes_hex(bytes2);
print_some_strange_data(); //idk what is this, it's not needed anyway :)
if(crypto_function(bytes2, user_input(), 16, some_bytes) == bytes1)
print crypto_function(bytes2, flag, 16, some_bytes);
}
user_input
is a function which reads data from the user.
Now let’s investigate crypto_function
.
I was sure that this isnt any new crypto but just from some library.
We can see that it calls various virtual methods from vtable.
After navigating to the memory of them we can gain more information.
For example above offset 73F500
is located the following string:
.data.rel.ro:000000000073F4F8 dq offset _ZTIN8CryptoPP14CTR_ModePolicyE ; `typeinfo for'CryptoPP::CTR_ModePolicy
.data.rel.ro:000000000073F500 unk_73F500 db 0
also this one is interesting:
.data.rel.ro:0000000000741BC8 dq offset _ZTIN8CryptoPP8Rijndael4BaseE ; `typeinfo for'CryptoPP::Rijndael::Base
.data.rel.ro:0000000000741BD0 unk_741BD0 db 0 ; DATA XREF: sub_406410+3CD↑o
So I just concluded that this is AES-128 encryption in CTR mode. I’ve set a breakpoint at this function and printed their arguments:
I came to the conclusion that the first argument is ctr, 4 is the key. I checked if my theory about this cipher function is correct - I copied arguments and output abd wrote the following python script:
from pwn import *
from crypto_commons.symmetrical import aes
def aes_encode(input):
global key
global ctr
AES = aes.AES()
AES.init(key)
w = AES.encrypt(ctr)
w = xor(input, w)
return w
def aes_decode(input):
global key
global ctr
AES = aes.AES()
AES.init(key)
w = AES.encrypt(ctr)
w = xor(input, w)
return w
key = "f70a0a0d0f00000d0b0a0a0d0f00000d" #wytestowac nowe kombinacje
ctr = "f3 e9 cf 98 bb 8d 94 58 43 61 21 f4 f8 e3 19 ad"
input = "a"*16
ctr = ctr.replace(" ","").decode("hex")
key = key.replace(" ","").decode("hex")
x = aes_encode(input)
print "encrypted user input: "+x.encode("hex")
print "the output from binary: 9bcefda8b86570db6d8330986472ac5e"
output:
a@x:~/Desktop/Authenticator$ python test.py
encrypted user input: 9bcefda8b86570db6d8330986472ac5e
the output from binary: 9bcefda8b86570db6d8330986472ac5e
It proves that my predictions were correct.
if we want to pass if(crypto_function(bytes2, user_input(), 16, some_bytes) == bytes1)
in main
function, it’s obvious, that user input needs to be equal the output of the decryption function AES-128 CTR mode with bytes1
as data to decrypt
The key to crypto_function
was the same at every run when ASLR was switched off.
When ASLR was switched on, the first byte of the key was different at every run.
I also checked this on different linux systems and it was the same.
So I wrote the exploit that connects to the server and tries to brute-force all possibilities of the first byte of the key:
from pwn import *
from crypto_commons.symmetrical import aes
def recvall(r):
d = ""
n = "a"
while n:
n = r.recv(timeout = 0.2)
d += n
return d
def aes_decode_(key,input,ctr):
print ctr
ctr = hex(ctr)[2:]
ctr = ctr.rjust(32,"0")
ctr = ctr.decode("hex")
AES = aes.AES()
AES.init(key)
w = AES.encrypt(ctr)
w = xor(input, w)
return w
def split_string(string, split_string):
return [string[i:i+split_string] for i in range(0, len(string), split_string)]
def aes_decode(key,input,ctr):
ctr = ctr.encode("hex")
ctr = int(ctr,16)
input = split_string(input, 16)
decrypted = ""
for i in input:
decrypted += aes_decode_(key, i, ctr)
ctr += 1
return decrypted
def try_key(key):
r = remote("46.101.180.78", 13031)
r.sendline("HELLO")
data = recvall(r)
print data
random1 = data.split("\n")[0]
random2 = data.split("\n")[1]
print "-----------"
print random1
print random2
random1 = random1.replace(" ","").decode("hex")
random2 = random2.replace(" ","").decode("hex")
key = key.decode("hex")
inp = aes_decode(key, random1, random2)
print inp.encode("hex")
r.send("1"+inp+"\n")
print "encrypted flag:"
encrypted_flag = r.recv()
print len(encrypted_flag)
print encrypted_flag
print "###"
decrypted = aes_decode(key,encrypted_flag,random2)
print decrypted
if "DCTF" in decrypted:
exit()
r.close()
for brut_byte in range(0x00,0x100):
gg = hex(brut_byte)[2:]
gg=gg.rjust(2,"0")
print gg
try_key(gg+"0a0a0d0f00000d0b0a0a0d0f00000d")
and the flag is:
DCTF{a1fee34f2a3e6e010d786f02865dc39896faa6b589d1f57f565bac9bd1d85cae}
Summing up, the task was very easy if you reversed the binary properly. The task was categoried wrongly and this could mislead people, maybe this is why this task hadn’t many solves.
我在最近的学习过程中,发现Powershell命令的历史记录有时会包含系统敏感信息,例如远程服务器的连接口令,于是我对Powershell的历史记录功能做了进一步研究,总结一些渗透测试中常用导出历史记录的方法,结合利用思路,给出防御建议。
本文将要介绍以下内容:
记录Powershell命令的历史记录有两种方式,可分别使用Get-History
和Get-PSReadlineOption
读取
参考文档:
https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Core/Get-History?view=powershell-3.0
默认Powershell v2及以上支持
能够记录当前会话中输入的命令,多个Powershell进程之间不共享,Powershell进程退出后自动清除所有记录
获得历史记录的完整信息:
Get-History | Format-List -Property *
包括:
测试如下图
删除所有历史记录:
Clear-History
按ID号删除命令:
Clear-History -Id 3
获得了一台Windows系统的权限,发现后台有Powershell进程,想要读取Powershell进程中的历史记录
(1)Powershell进程无法接收键盘输入命令
例如Powershell加载了一个在后台运行的脚本:Powershell -ep bypass -f 1.ps1
此时无法向Powershell进程发送键盘消息,这时可以通过读取进程的命令行参数获得有用的信息,开源代码:
https://github.com/3gstudent/Homework-of-C-Language/blob/master/GetProcessCommandLine.cpp
代码实现了读取指定进程的命令行参数,通常能够获得有用的信息
(2)Powershell进程能够接收键盘输入命令
这里可以模拟发送键盘消息,导出历史记录
程序实现思路:
程序细节:
1.Virtual-Key Codes
每一个键盘输入消息对应一个Virtual-Key Code
参考资料: https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes
需要模拟键盘按下和键盘抬起两个操作,开源的测试代码:
https://github.com/3gstudent/Homework-of-C-Language/blob/master/SendKeyboardMessageToPowershell.cpp
代码实现了搜索指定pid的进程,向进程发送键盘消息,内容为:whoami
2.导出历史记录
命令如下:
Get-History|export-csv $env:temp"\history.csv"
其中需要考虑字符"|"
、"$"
和"""
,模拟键盘输入时需要加Shift键
这里的实现方法是先使用keybd_event
按下Shift键
,再用PostMessage
发送按键的字母,最后抬起两个按键
开源的测试代码:
https://github.com/3gstudent/Homework-of-C-Language/blob/master/SendKeyboardMessageToPowershell(Get-History).cpp
代码实现了搜索指定pid的进程,向进程发送键盘消息,内容为:Get-History|export-csv $env:temp"\history.csv"
命令如下:
doskey /h
清空:
doskey /reinstall
也可以通过发送键盘消息的方式导出cmd.exe的命令历史记录
参考文档:
https://docs.microsoft.com/en-us/powershell/module/psreadline/?view=powershell-5.1
默认Powershell v5支持
Powershell v3和Powershell v4需要安装Get-PSReadlineOption后才可以使用
安装后,所有Powershell命令的历史记录会保存在同一位置,可随时查看
这里以64位系统为例,安装方法如下:
(1)安装PowerShellGet
下载:
https://www.microsoft.com/en-us/download/details.aspx?id=51451
注:
安装前需要关闭powershell进程
可以通过命令行实现隐蔽安装,命令如下:
msiexec /q /i PackageManagement_x64.msi
安装成功后,在控制面板的已安装程序列表(Control Panel\Programs\Programs and Features)有显示:Package Management Preview - x64
可以通过删除对应的注册表项进行隐藏,更多细节可参考《渗透基础——获得当前系统已安装的程序列表》
Package Management Preview - x64
的注册表路径为HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{57E5A8BB-41EB-4F09-B332-B535C5954A28}
只需要删除这个注册表项及子项即可实现在已安装程序列表中隐藏
删除注册表项的cmd命令:
reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{57E5A8BB-41EB-4F09-B332-B535C5954A28} /f
(2)安装PSReadLine
通过Install-Module命令安装
Install-Module -Name PSReadLine
弹出提示:
NuGet provider is required to continue
PowerShellGet requires NuGet provider version '2.8.5.201' or newer to interact
with NuGet-based repositories. The NuGet provider must be available in
'C:\Program Files\PackageManagement\ProviderAssemblies' or
'C:\Users\Administrator\AppData\Local\PackageManagement\ProviderAssemblies'.
You can also install the NuGet provider by running 'Install-PackageProvider
-Name NuGet -MinimumVersion 2.8.5.201 -Force'. Do you want PowerShellGet to
install and import the NuGet provider now?
[Y] Yes [N] No [S] Suspend [?] Help (default is "Y"):
需要再次输入Y
进行安装
如果需要实现一键安装,可以先安装NuGet,再安装PSReadLine,完整命令如下:
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Install-Module -Name PSReadLine
(3)使用
所有powershell命令将会保存在固定位置:%appdata%\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt
查看命令的历史记录:
Get-Content (Get-PSReadlineOption).HistorySavePath
清除命令的历史记录:
Remove-Item (Get-PSReadlineOption).HistorySavePath
获得了Windows系统的访问权限,首先查看Powershell版本,如果是v5,可通过读取文件%appdata%\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt
获得历史记录
如果系统是Powershell v3或Powershell v4,可通过命令行安装PSReadLine,这样就能记录后续系统所有的Powershell命令
如果使用高版本的Windows系统,如Win10,默认Powershell版本为5.0,会记录Powershell的命令,建议定时进行清除,位置:%appdata%\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt
清除命令的历史记录:
Remove-Item (Get-PSReadlineOption).HistorySavePath
对于低版本的Powershell,如果命令中包含敏感信息(如远程连接的口令),需要及时清除,命令为:Clear-History
对于cmd.exe,如果命令中包含敏感信息(如远程连接的口令),需要及时清除,命令为:doskey /reinstall
本文介绍了两种Powershell命令的历史记录,总结常用导出历史记录的方法,结合利用思路,给出防御建议。
最近遇到了一个有趣的问题: 我在尝试使用wmi获取当前系统已安装的程序列表时,并不能获得完整的列表。于是做了进一步研究,找出错误原因,改变思路,完成目标。
本文是一篇介绍基础知识的文章,用来解决基本的问题。
本文将要介绍以下内容:
代码如下:
Get-WmiObject -class Win32_Product
对输出结果进行过滤,只显示程序名称,代码如下:
Get-WmiObject -class Win32_Product |Select-Object -Property name
获得结果如下图
代码如下:
wmic /NAMESPACE:"\\root\CIMV2" PATH Win32_Product
对输出结果进行过滤,只显示程序名称,代码如下:
wmic /NAMESPACE:"\\root\CIMV2" PATH Win32_Product get name /FORMAT:table
获得结果如下图
下载地址:
https://wmie.codeplex.com/releases/view/135794
界面化的WMI查询工具,可用来查询wmi支持的类,是研究wmi的好工具
首先点击Connect
连接本机
选中ROOT\CIMV2
-> Query
输入查询命令:
SELECT * FROM Win32_Product
获得结果如下图
控制面板
-> 程序
-> 程序和功能
发现部分程序通过wmi查询无法获得,例如Google Chrome,对比结果如下图
通过WMI查询Win32_Product只能获得特定的程序列表
这些程序有一个共同的特征: 安装包由Windows Installer制作,安装过程中调用Windows Installer服务进行安装
说明:
Microsoft Windows Installer: Windows 操作系统的一个组件,是安装和卸载软件的标准基础。
Windows Installer服务: 添加、修改和删除作为Windows Installer程序包提供的应用程序。
除了Microsoft Windows Installer,制作安装包还可使用EasySetup、Setup2Go、Advanced Installer、Qt installer framework和WinRAR
Chrome的在安装过程中不会调用Microsoft Windows Installer组件,所以通过WMI查询Win32_Product无法找到Chrome
我们知道,通过控制面板
-> 程序
-> 程序和功能
获取的程序列表比较完整,该列表对应注册表键值:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\
每个子健代表列表中的一个程序
所以,可以通过枚举注册表键值的方法获得完整程序列表
值得注意的是64位系统下,注册表存在重定向的问题,也会影响程序列表的显示
32位程序列表对应注册表键值HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\
64位程序列表对应注册表键值HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\
注:
这个问题在之前的文章《关于32位程序在64位系统下运行中需要注意的重定向问题》进行过整理
编写powershell脚本实现枚举注册表,获得完整的程序列表
关键代码:
dir Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall -Name
如下图
(Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{4F3742E0-700E-431D-BF19-5B27ED98E8F1}").DisplayName
如下图
$RegPath = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
$QueryPath = dir $RegPath -Name
foreach($Name in $QueryPath)
{
(Get-ItemProperty -Path $RegPath$Name).DisplayName
}
完整代码可参考如下地址:
https://github.com/3gstudent/ListInstalledPrograms
通常,已安装的程序会创建快捷方式,所以,尝试枚举快捷方式文件也能获得完整的程序列表
通过wmic获取所有快捷方式:
wmic PATH Win32_ShortcutFile get name /FORMAT:table
本文介绍了通过wmi无法获得当前系统已安装程序完整列表的原因,编写powershell脚本,通过枚举注册表项,实现获得程序完整列表。作为一篇介绍基础知识的文章,希望能给新人带来启发。
为了验证PE文件的来源和完整性,常常会为PE文件添加数字证书。Windows系统下默认会对一些重要文件添加微软的数字签名,如ntdll.dll。恶意文件分析系统在对PE文件的静态分析过程中,如果PE文件有数字签名,则对签名进行验证。若数字签名验证通过,则不再对其进行后续分析。这样做主要考虑的是降低误报,以及减少服务器资源消耗。如果能在保证数字签名有效的前提下,在PE文件中隐藏Payload,那么这种隐写方式将会非常隐蔽。
来自Deep Instinct Research Team的Tom Nipravsky
在BlackHat2016的议题《Certificate Bypass: Hiding and Executing Malware from a Digitally Signed Executable》
介绍了这个方法,并且实现了一个Reflective PE Loader,用来加载隐藏在PE文件数字证书中的Payload,值得学习。
议题PDF下载地址:
https://www.blackhat.com/docs/us-16/materials/us-16-Nipravsky-Certificate-Bypass-Hiding-And-Executing-Malware-From-A-Digitally-Signed-Executable-wp.pdf
本文将会更加详细的介绍如何实现在保证数字签名有效的前提下,向PE文件中隐藏Payload。
图1引用自Windows Authenticode Portable Executable Signature Format https://msdn.microsoft.com/en-us/windows/hardware/gg463180.aspx
签名过程:
Certificate Table
计算文件hash的步骤:
引用自Windows Authenticode Portable Executable Signature Format https://msdn.microsoft.com/en-us/windows/hardware/gg463180.aspx
如果修改了文件内容,那么计算出的文件hash就会改变,导致数字证书无法通过验证,所以数字证书能够保证签名文件的完整性,但是在计算文件hash的算法上存在一个不足:
计算文件hash并非对整个文件内容作计算(如计算文件hash的步骤4,以及图1中灰色背景的部分,目的是避免绑定的证书文件影响到hash值)
更值得注意的是:
在Certificate Table的尾部添加数据并不会影响计算出的文件hash,也就是说在Certificate Table尾部添加数据不会导致证书失效
注:
这个思路早在2009年由Aymeric Barthe@bartheph提出
https://blog.barthe.ph/2009/02/22/change-signed-executable/
当然,在证书尾部添加数据虽然不会影响计算出的文件hash,但会改变证书长度,所以在PE文件结构中保存证书长度的位置需要作相应修改(共2处),下面实例演示一种最直观的添加payload并修改证书长度的方法
测试文件:
ntdll.dll
Win7 x64下默认位置为:C:\Windows\SysWOW64
使用工具:
CFF Explorer
Hex Editor
LordPE
使用CFF Explorer
查看dll结构,如图
可获得如下信息:
File Size: 1292592 bytes
PE Size: 1277952 bytes
推断出:
Certificate Table的偏移地址为138000H(1277952)
Certificate Table的前四字节保存长度,大小应该为14640 bytes(1292592-1277952)
现在跳到偏移地址138000H,查看前四字节,验证推断
如图,前四字节为30390000,转换成实际长度为00003930H,即14640 bytes
测试待添加的payload为:1111111111,长度为10
显然,
New Size = Old Size + Payload Size
= 14640 +10
= 14650
= 393aH
对应偏移地址138000H-138003的数据修改为3A390000,如图
使用CFF Explorer
查看dll结构,选择Nt Headers-Optional Header-Data Directories [x],找到Security Directory Size项,如图
00003930修改为0000393A,如图
保存文件,查看文件信息,签名失效(因为还没有添加payload)
如图
使用Hex Editor
在文件尾部添加payload
如图
保存后,签名成功识别,如图
使用LordPE
打开PE文件,如图,原文件的校验和为0013E00E
点击”?”对其更新,如图,新的校验和为00142672
使用CFF Explorer
打开PE文件,选择Nt Headers-Optional Header,找到CheckSum项
原校验和为0013E00E,如图
修改为00142672,保存为ntdll(AddPayload).dll
使用LordPE
验证校验和,成功
至此,在保证PE文件数字证书有效的前提下,成功在PE文件尾部添加Payload
注:
添加的payload长度需要满足为8的整数倍,否则会显示数字签名状态无效
测试文件:aliide.sys
如图,偏移地址2000H(8192)
跳到偏移地址2000H,查看前四字节,如图
Certificate Size为00001c50H
添加的payload为BBBBBBBBBB,10字节
00001c50H+10=00001c5AH
修改为5A1C0000,如图
如图
00001C50改为00001C5A
尾部添加BBBBBBBBBB
如图
000065ED改为0000B156
添加成功
注:
添加的payload长度需要满足为8的整数倍,否则会显示数字签名状态无效
开发语言:c++
下载地址:
https://blog.barthe.ph/download/2009/AppendPayLoad.tar.bz2
编译成功后,命令行执行:
AppendPayLoad.exe ntdll.dll payload.txt newntdll.dll
参数说明:
ntdll.dll:原PE文件
payload.txt:存储待添加的payload
newntdll.dll:新生成的文件
测试Payload添加成功,新生成文件的数字签名成功识别,程序有如下特点:
1.payload在尾部自动填0补齐payload长度为8的倍数
如图,多了6个’00’,补齐长度
2.未修改PE文件校验和
如图,PE文件校验和实际应该为00142684
开发语言:Autoit
下载地址:
http://reboot.pro/files/file/85-digitalsignaturetweaker/
界面如图
本文介绍了如何利用工具实现在保证数字签名有效的前提下,向PE文件中隐藏Payload。在掌握了修改方法后,编写程序实现自动修改不会很难。对于带有数字签名的PE文件,建议不要盲目相信。