爆破内存中的SWF文件

因为最近有一点需要,所以想提取打开的网页里面的SWF文件出来,其实以前也做过,用个游戏修改器,搜索一下FWS然后挨个检查一下结果,手工复制一下内存数据。这次的却比较多,挨个弄比较麻烦还容易出错。于是写了一小段程序。只是需要注意的是,很多浏览器并不是那个有启动窗口的进程是我们要的……哎……不提这个,只是提一下这个实现。其实嘿嘿,前面那个从OFFICE中提取的,也可以考虑一下用这个代替?~咕~~(╯﹏╰)b~速度,速度……慢点点而已了

 

1、枚举进程,列表以供选择

2、枚举所选进程内存块,搜索FWS字样……貌似叫暴力……(其实只需稍加修改源程序就可以连同CWS一起搜索)

3、筛选,依据被定为这样几个:

A、版本(第四字节)为,7,8,9,10的

B、文件大小大于0(5-8字节)

C、文件结尾为0X40,0X00,0X00,0X00的

 

第一部分,枚举进程其实没什么好说的,Process类就可以了。

第二部分,其实就是核心内容了:内存检索,一般来说,应该先枚举进程所用的内存块及其属性,这样可以通过属性进行筛选,但实际在实现时,我是用ReadProcessMemory函数是否出错来决定是否继续搜索本块内存的……真是懒人啊~~~~

 

 

代码
Public Structure MEMORY_BASIC_INFORMATION
        
Dim BaseAddress As Integer        
        
Dim AllocationBase As Integer     
        
Dim AllocationProtect As Integer  
        
Dim RegionSize As Integer         
        
Dim State As Integer              
        
Dim Protect As Integer            
        
Dim lType As Integer              
    
End Structure
‘出处http://www.cnblogs.com/zcsor/
    
Private Declare Function VirtualQueryEx Lib "kernel32" (ByVal hProcess As Int32, ByVal lpAddress As IntPtr, ByRef lpBuffer As MEMORY_BASIC_INFORMATION, ByVal dwLength As Int32) As Int32
    
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As IntegerByVal lpBaseAddress As IntegerByVal lpBuffer() As ByteByVal nSize As IntegerByRef lpNumberOfBytesWritten As IntegerAs Integer
    
Private Shared m_phandle As Integer

 

 

这样就声明了所用的API函数,接下来是枚举过程:

 

 

代码
Private Shared Function GetMemoryInfo(ByVal pHandle As IntegerAs ArrayList
        
Dim Infs As New ArrayList
        
Dim pAddr As Integer, dwTotalCommit As Integer, ret As Integer, miLen As Integer
        
Dim mi As New MEMORY_BASIC_INFORMATION
        miLen 
= Len(mi)
        dwTotalCommit 
= 0 '这是结果
        pAddr = 0  '这个时查询起始地址,设为0,即进程虚拟地址开始处。
        ret = VirtualQueryEx(pHandle, pAddr, mi, miLen) '从起始地址开始查询
        Infs.Add(mi)
        
Do While (ret = miLen)
            dwTotalCommit 
= dwTotalCommit + mi.RegionSize
            pAddr 
= mi.BaseAddress + mi.RegionSize '跳过已经查询过的内存块,到未被查询的内存地址起始处
            ret = VirtualQueryEx(pHandle, pAddr, mi, miLen) '再次查询,直到查询失败(所有可查询地址都已经查过了)
            If mi.State = &H1000 Then Infs.Add(mi)
        
Loop
        
Return Infs
    
End Function

 

 

 很简单,相信大家一看就懂~~~~~~~~~~接下来,就是读内存数据了,这里需要考虑这样一个问题:有些内存块大的……可怜的VB溢出了咋办……前几天绘制一个几十万像素宽的图像就……咕~~(╯﹏╰)b,其实解决办法很简单的,分块即可,这里读写内存我们就分1024字节吧~~当然有一定原因了~~分4096也许你喜欢?O(∩_∩)O~其实编码起来都差不多,只要你知道~~~原因

 出处:http://www.cnblogs.com/zcsor/

 

代码

    
Public Shared Function Scan(ByVal pHandle As IntegerAs ArrayList
        m_phandle 
= pHandle
        
If Not ToKen.ToKenPrivileges() Then MsgBox("提升权限失败,扫描结果可能有遗漏")
        
Dim Ret As New ArrayList
        
Dim int As ArrayList = GetMemoryInfo(pHandle)
        
For Each mi As MEMORY_BASIC_INFORMATION In int
            
Dim bLen As Integer = mi.RegionSize
            
Dim rLen As Integer
            
Dim mBaseAddr As Integer = mi.BaseAddress
            
Dim mStep As Integer = 1024
            
Dim test(3As Byte
            
Do While bLen > 0
                
If bLen > mStep Then rLen = mStep Else rLen = bLen
                bLen 
-= mStep
                
Dim Bytes(rLen - 1As Byte
                
Dim read As Integer = ReadProcessMemory(pHandle, mBaseAddr, Bytes, rLen, 0)
                
If read = 0 Then Exit Do
                
For mIndex = 0 To mStep - 3 Step 4
                    
If Bytes(mIndex) = &H46 AndAlso Bytes(mIndex + 1= &H57 AndAlso Bytes(mIndex + 2= &H53 Then  'just FWS
                        Dim f As New Flash
                        f.addr 
= mIndex + mBaseAddr
                        f.ver 
= Bytes(mIndex + 3)
                        f.size 
= System.BitConverter.ToInt32(Bytes, 4)
                        
If f.size > 0 AndAlso f.ver > 6 AndAlso f.ver < 11 Then
                            read 
= ReadProcessMemory(pHandle, mBaseAddr + mIndex + f.size - 4, test, 40)
                            
If read = 0 Then
                                
Exit Do
                            
Else
                                
If test(0= &H40 AndAlso test(1= 0 AndAlso test(2= 0 AndAlso test(3= 0 Then Ret.Add(f)
                            
End If
                        
End If
                    
End If
                
Next
                mBaseAddr 
+= mStep
            
Loop
        
Next
        
Return Ret
    
End Function

    
Structure Flash
        
Public addr As Integer
        
Public ver As Integer
        
Public size As Integer
        
Public Overrides Function ToString() As String
            
Return "addr: " & Hex(addr) & vbCrLf & _
            
"ver:  " & ver & vbCrLf & _
            
"size: " & Format(size, "#,0."& vbCrLf
        
End Function
    
End Structure

 

 

 

这样,大功告成了啊~得到了可读的内存空间内的全部貌似SWF文件的信息,接下来……保存它们吧!

 

代码
    Shared Function Save2File(ByVal Pid As IntegerByVal addr As IntegerByVal size As IntegerAs Boolean
        
Dim bs(size - 1As Byte
        
Dim read As Integer = ReadProcessMemory(m_phandle, addr, bs, size, 0)
        
If read = 0 Then
            
Return False
        
Else
            My.Computer.FileSystem.WriteAllBytes(
"c:\" & Hex(Pid) & "_" & Hex(addr) & ".swf", bs, False)
        
End If
    
End Function

 

 

呃,发现我确实很懒了吧……其实也检测了一下,当读内存失败的时候不保存(也没法保存嘛~),这是防止FWS字样出现的位置后面的字节数不够SIZE(超出内存段)时的错误,换句话说,就是如果代码没写错,那这个FWS一定不是一个FLASH文件~

’出处http://www.cnblogs.com/zcsor/

最后附上,成品~呃,其实你自己写一下修改修改我的代码,才真的是成品,这个里面不识别压缩的~~其实压缩的和这个一样的~~~~如果你愿意解压,那就解压吧~几句代码的事……不过我懒

 

 

 

/Files/zcsor/FLASH提取工具.7z

 

 

 

 

 

今天换了笔记本测试的时候发现了一个API调用的问题,重新修改如下:

 

    Structure MEMORY_BASIC_INFORMATION ' 28 bytes
        Dim BaseAddress As Integer
        Dim AllocationBase As Integer
        Dim AllocationProtect As Integer
        Dim RegionSize As Integer
        Dim State As Integer
        Dim Protect As Integer
        Dim lType As Integer
    End Structure

    Private Declare Function VirtualQueryEx Lib "kernel32" (ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, ByRef lpBuffer As MEMORY_BASIC_INFORMATION, ByVal dwLength As UInteger) As Integer
   

原来的代码在笔记本上运行昨天还可以,今天却出现错误,原因尚未查明。改成以上声明形式工作正常。

 

又详细的查了一下SWF加载的特征,确定其按一定特征的基地址加载(&HXXXXX000)于是优化查找逻辑如下:


    Public Shared Function Scan(ByVal pHandle As Integer) As ArrayListm_phandle = pHandle
        Dim Ret As New ArrayList
        Try
            Dim int As ArrayList = GetMemoryInfo(pHandle)
            For Each mi As MEMORY_BASIC_INFORMATION In int
                Dim bLen As Integer = mi.RegionSize
                'Dim lOldProtect, LOL As Integer
                Dim mBaseAddr As Integer = mi.BaseAddress
                Dim mStep As Integer = 4096
                Dim test(3) As Byte
                'lOldProtect = VirtualProtectEx(pHandle, mi.BaseAddress, 1, &H40, lOldProtect)
                Do While bLen >= 0
                    bLen -= mStep
                    Dim Bytes(7) As Byte
                    Dim read As Integer = ReadProcessMemory(pHandle, mBaseAddr, Bytes, 8, 0)
                    If read = 0 Then Exit Do
                    If Bytes(0) = &H46 AndAlso Bytes(1) = &H57 AndAlso Bytes(2) = &H53 Then  'just FWS
                        Dim f As New Flash
                        f.addr = mBaseAddr
                        f.ver = Bytes(3)
                        f.size = System.BitConverter.ToInt32(Bytes, 4)
                        If f.size > 0 AndAlso f.ver > 8 AndAlso f.ver < 11 AndAlso (Integer.MaxValue - mBaseAddr - f.size >= 0) Then
                            read = ReadProcessMemory(pHandle, mBaseAddr + f.size - 4, test, 4, 0)
                            If read = 0 Then
                                Exit Do
                            Else
                                If test(0) = &H40 AndAlso test(1) = 0 AndAlso test(2) = 0 AndAlso test(3) = 0 Then Ret.Add(f)
                            End If
                        End If
                    End If
                    mBaseAddr += mStep
                Loop
                ' LOL = VirtualProtectEx(pHandle, mi.BaseAddress, 1, lOldProtect, LOL)
            Next
            Return Ret
        Catch ex As Exception
            MsgBox(ex.Message & vbCrLf & ex.Source & vbCrLf & ex.GetBaseException.ToString)
        End Try
        Return Ret
    End Function

可能还存在一些问题,以后发现会继续修正的。

 

 

补充两点内容,有朋友问这个软件的适用范围和一些更新的查找函数,并说不太喜欢我写东西时留下一些已经被我修复或优化的过程不发出来而是发原始代码。说实在的,只要更新了后来的查找函数,就可以找到全部SWF(只要时机是恰当的,我还是不想说明什么叫恰当的时机,事实上,加载完并播放的时候,时机就很恰当,具体原因非常繁杂,不要太过深究了):

首先,不管是加密也好,不加密也好,压缩也好,不压缩也好(我的代码没有处理压缩的,实际上只需要了解压缩的是以什么开头,是以什么结尾,大小如何计算——这里有些人是误导的,第4-8字节,是压缩后的大小,而不是压缩前。即4-8字节总是指示文件所占的实际字节数。),鉴于FLASH最终只能执行顺序且连续的文件流,所以在某一时刻(这就是你的恰当时机),SWF文件一定是以未加密的形式出现在FLASH虚拟机面前!

其次,在后来的代码中(其实前面我写的时候确实留下这个问题给细心的朋友,但也是一种误导,在此表示歉意。因为那是原来的是个带有内存搜索和代码调试功能的游戏修改器中的部分代码,最初我未经修改就进行了使用——虽然注意到了步长问题,但当时没有明确提出而是使用未经修改和优化的代码进行的4字节对齐搜索)使用的步长是4096字节——每隔4096字节(&H1000)去搜索一次是否为FWS,这是完全合理的,关于这一点可以参考ADOBE的关于AS3内存管理那部分内容,它每当需要新内存时首先尝试回收旧的然后申请新的,并以&H1000为单位进行申请。结合其对齐内存的原因,可以断定,SWF就出现在我后来代码所搜索的位置,而不是其他位置。

 

今天进行了一些思考,主要是我们的代码的搜索方式,其实还可以优化,一方面,我们首先枚举进程,在这之后就进入了搜索,实际上完全可以进一步枚举每进程是否含有FLASHXX.OCX,而断定是否对进程内存进行搜索,这将提高效率。另一方面,我们进行全内存的搜索,这也是一个低效的做法——虽然代码加以优化后速度快了一些,但更有效的做法是改变思路……暴力搜索只在需要时才用……例如还不清楚这些SWF是被如何的过程存放的,例如想获取一些“私有”的东东时……………………也就是说我们对FLASH存储SWF的表进行解析,完全可以直接得到内存地址,我还没有找到相关资料——我确信这种门牌号技术被应用到这里,但可以确定的是我在内存中确实发现了这样的存储结构(表),虽然有些结构内容还不清楚,而且在我进行一些注入和对指针的探索之后发现——表消失了……嘎嘎,被摆了一道,下次一定要把各个线程搞挺再干。去查查相关资料吧,不然只好自己动手丰衣足食了,不过OD到现在还不咋地,嘿~开工去

posted @ 2010-12-24 14:31  zcsor~流浪dè风  Views(4098)  Comments(3Edit  收藏  举报