赞
踩
格式:
*.IPA IOS系统的app文件格式
*.APK 安卓系统的app文件格式
防止APK被逆向,防篡改,实现数据保护
APK加壳的中了非常多,我在取证过程中所见到的加壳种类有UPX和pyintaller的加壳方式
一般我们用雷电挂载APK时可以直接使用雷电自带的脱壳来脱壳之后反编译。但是有些恶意文件不能用雷电来挂载,这个时候我们就要手动查壳
Detect It Easy3.7(之前老的版本可能查不到pyinstaller这个加壳方式)
PEiD:偶尔用,效果不是很好
当然可以用沙箱的方法看一下他是不是有壳
知道是什么壳加固了的话,就可以对症下药了
如果是UPX壳的话就用UPX tool来脱
或者360壳,使用取证工具来脱
如果是pyinstaller壳的话用脚本来脱,将脚本和恶意文件放到一个文件夹下面,用cmd跑,会得到一个文件夹,文件夹里的文件不带pyc后缀,要自己加上,然后这些文件也缺少文件头,还要自己补充
然后可以使用在线pyc反编译
- """
- PyInstaller Extractor v1.9 (Supports pyinstaller 3.3, 3.2, 3.1, 3.0, 2.1, 2.0)
- Author : Extreme Coders
- E-mail : extremecoders(at)hotmail(dot)com
- Web : https://0xec.blogspot.com
- Date : 29-November-2017
- Url : https://sourceforge.net/projects/pyinstallerextractor/
- For any suggestions, leave a comment on
- https://forum.tuts4you.com/topic/34455-pyinstaller-extractor/
- This script extracts a pyinstaller generated executable file.
- Pyinstaller installation is not needed. The script has it all.
- For best results, it is recommended to run this script in the
- same version of python as was used to create the executable.
- This is just to prevent unmarshalling errors(if any) while
- extracting the PYZ archive.
- Usage : Just copy this script to the directory where your exe resides
- and run the script with the exe file name as a parameter
- C:\path\to\exe\>python pyinstxtractor.py <filename>
- $ /path/to/exe/python pyinstxtractor.py <filename>
- Licensed under GNU General Public License (GPL) v3.
- You are free to modify this source.
- CHANGELOG
- ================================================
- Version 1.1 (Jan 28, 2014)
- -------------------------------------------------
- - First Release
- - Supports only pyinstaller 2.0
- Version 1.2 (Sept 12, 2015)
- -------------------------------------------------
- - Added support for pyinstaller 2.1 and 3.0 dev
- - Cleaned up code
- - Script is now more verbose
- - Executable extracted within a dedicated sub-directory
- (Support for pyinstaller 3.0 dev is experimental)
- Version 1.3 (Dec 12, 2015)
- -------------------------------------------------
- - Added support for pyinstaller 3.0 final
- - Script is compatible with both python 2.x & 3.x (Thanks to Moritz Kroll @ Avira Operations GmbH & Co. KG)
- Version 1.4 (Jan 19, 2016)
- -------------------------------------------------
- - Fixed a bug when writing pyc files >= version 3.3 (Thanks to Daniello Alto: https://github.com/Djamana)
- Version 1.5 (March 1, 2016)
- -------------------------------------------------
- - Added support for pyinstaller 3.1 (Thanks to Berwyn Hoyt for reporting)
- Version 1.6 (Sept 5, 2016)
- -------------------------------------------------
- - Added support for pyinstaller 3.2
- - Extractor will use a random name while extracting unnamed files.
- - For encrypted pyz archives it will dump the contents as is. Previously, the tool would fail.
- Version 1.7 (March 13, 2017)
- -------------------------------------------------
- - Made the script compatible with python 2.6 (Thanks to Ross for reporting)
- Version 1.8 (April 28, 2017)
- -------------------------------------------------
- - Support for sub-directories in .pyz files (Thanks to Moritz Kroll @ Avira Operations GmbH & Co. KG)
- Version 1.9 (November 29, 2017)
- -------------------------------------------------
- - Added support for pyinstaller 3.3
- - Display the scripts which are run at entry (Thanks to Michael Gillespie @ malwarehunterteam for the feature request)
- """
-
- from __future__ import print_function
- import os
- import struct
- import marshal
- import zlib
- import sys
- import imp
- import types
- from uuid import uuid4 as uniquename
-
-
- class CTOCEntry:
- def __init__(self, position, cmprsdDataSize, uncmprsdDataSize, cmprsFlag, typeCmprsData, name):
- self.position = position
- self.cmprsdDataSize = cmprsdDataSize
- self.uncmprsdDataSize = uncmprsdDataSize
- self.cmprsFlag = cmprsFlag
- self.typeCmprsData = typeCmprsData
- self.name = name
-
-
- class PyInstArchive:
- PYINST20_COOKIE_SIZE = 24 # For pyinstaller 2.0
- PYINST21_COOKIE_SIZE = 24 + 64 # For pyinstaller 2.1+
- MAGIC = b'MEI\014\013\012\013\016' # Magic number which identifies pyinstaller
-
- def __init__(self, path):
- self.filePath = path
-
-
- def open(self):
- try:
- self.fPtr = open(self.filePath, 'rb')
- self.fileSize = os.stat(self.filePath).st_size
- except:
- print('[*] Error: Could not open {0}'.format(self.filePath))
- return False
- return True
-
-
- def close(self):
- try:
- self.fPtr.close()
- except:
- pass
-
-
- def checkFile(self):
- print('[*] Processing {0}'.format(self.filePath))
- # Check if it is a 2.0 archive
- self.fPtr.seek(self.fileSize - self.PYINST20_COOKIE_SIZE, os.SEEK_SET)
- magicFromFile = self.fPtr.read(len(self.MAGIC))
-
- if magicFromFile == self.MAGIC:
- self.pyinstVer = 20 # pyinstaller 2.0
- print('[*] Pyinstaller version: 2.0')
- return True
-
- # Check for pyinstaller 2.1+ before bailing out
- self.fPtr.seek(self.fileSize - self.PYINST21_COOKIE_SIZE, os.SEEK_SET)
- magicFromFile = self.fPtr.read(len(self.MAGIC))
-
- if magicFromFile == self.MAGIC:
- print('[*] Pyinstaller version: 2.1+')
- self.pyinstVer = 21 # pyinstaller 2.1+
- return True
-
- print('[*] Error : Unsupported pyinstaller version or not a pyinstaller archive')
- return False
-
-
- def getCArchiveInfo(self):
- try:
- if self.pyinstVer == 20:
- self.fPtr.seek(self.fileSize - self.PYINST20_COOKIE_SIZE, os.SEEK_SET)
-
- # Read CArchive cookie
- (magic, lengthofPackage, toc, tocLen, self.pyver) = \
- struct.unpack('!8siiii', self.fPtr.read(self.PYINST20_COOKIE_SIZE))
-
- elif self.pyinstVer == 21:
- self.fPtr.seek(self.fileSize - self.PYINST21_COOKIE_SIZE, os.SEEK_SET)
-
- # Read CArchive cookie
- (magic, lengthofPackage, toc, tocLen, self.pyver, pylibname) = \
- struct.unpack('!8siiii64s', self.fPtr.read(self.PYINST21_COOKIE_SIZE))
-
- except:
- print('[*] Error : The file is not a pyinstaller archive')
- return False
-
- print('[*] Python version: {0}'.format(self.pyver))
-
- # Overlay is the data appended at the end of the PE
- self.overlaySize = lengthofPackage
- self.overlayPos = self.fileSize - self.overlaySize
- self.tableOfContentsPos = self.overlayPos + toc
- self.tableOfContentsSize = tocLen
-
- print('[*] Length of package: {0} bytes'.format(self.overlaySize))
- return True
-
-
- def parseTOC(self):
- # Go to the table of contents
- self.fPtr.seek(self.tableOfContentsPos, os.SEEK_SET)
-
- self.tocList = []
- parsedLen = 0
-
- # Parse table of contents
- while parsedLen < self.tableOfContentsSize:
- (entrySize, ) = struct.unpack('!i', self.fPtr.read(4))
- nameLen = struct.calcsize('!iiiiBc')
-
- (entryPos, cmprsdDataSize, uncmprsdDataSize, cmprsFlag, typeCmprsData, name) = \
- struct.unpack( \
- '!iiiBc{0}s'.format(entrySize - nameLen), \
- self.fPtr.read(entrySize - 4))
-
- name = name.decode('utf-8').rstrip('\0')
- if len(name) == 0:
- name = str(uniquename())
- print('[!] Warning: Found an unamed file in CArchive. Using random name {0}'.format(name))
-
- self.tocList.append( \
- CTOCEntry( \
- self.overlayPos + entryPos, \
- cmprsdDataSize, \
- uncmprsdDataSize, \
- cmprsFlag, \
- typeCmprsData, \
- name \
- ))
-
- parsedLen += entrySize
- print('[*] Found {0} files in CArchive'.format(len(self.tocList)))
-
-
-
- def extractFiles(self):
- print('[*] Beginning extraction...please standby')
- extractionDir = os.path.join(os.getcwd(), os.path.basename(self.filePath) + '_extracted')
-
- if not os.path.exists(extractionDir):
- os.mkdir(extractionDir)
-
- os.chdir(extractionDir)
-
- for entry in self.tocList:
- basePath = os.path.dirname(entry.name)
- if basePath != '':
- # Check if path exists, create if not
- if not os.path.exists(basePath):
- os.makedirs(basePath)
-
- self.fPtr.seek(entry.position, os.SEEK_SET)
- data = self.fPtr.read(entry.cmprsdDataSize)
-
- if entry.cmprsFlag == 1:
- data = zlib.decompress(data)
- # Malware may tamper with the uncompressed size
- # Comment out the assertion in such a case
- assert len(data) == entry.uncmprsdDataSize # Sanity Check
-
- with open(entry.name, 'wb') as f:
- f.write(data)
-
- if entry.typeCmprsData == b's':
- print('[+] Possible entry point: {0}'.format(entry.name))
-
- elif entry.typeCmprsData == b'z' or entry.typeCmprsData == b'Z':
- self._extractPyz(entry.name)
-
-
- def _extractPyz(self, name):
- dirName = name + '_extracted'
- # Create a directory for the contents of the pyz
- if not os.path.exists(dirName):
- os.mkdir(dirName)
-
- with open(name, 'rb') as f:
- pyzMagic = f.read(4)
- assert pyzMagic == b'PYZ\0' # Sanity Check
-
- pycHeader = f.read(4) # Python magic value
-
- if imp.get_magic() != pycHeader:
- print('[!] Warning: The script is running in a different python version than the one used to build the executable')
- print(' Run this script in Python{0} to prevent extraction errors(if any) during unmarshalling'.format(self.pyver))
-
- (tocPosition, ) = struct.unpack('!i', f.read(4))
- f.seek(tocPosition, os.SEEK_SET)
-
- try:
- toc = marshal.load(f)
- except:
- print('[!] Unmarshalling FAILED. Cannot extract {0}. Extracting remaining files.'.format(name))
- return
-
- print('[*] Found {0} files in PYZ archive'.format(len(toc)))
-
- # From pyinstaller 3.1+ toc is a list of tuples
- if type(toc) == list:
- toc = dict(toc)
-
- for key in toc.keys():
- (ispkg, pos, length) = toc[key]
- f.seek(pos, os.SEEK_SET)
-
- fileName = key
- try:
- # for Python > 3.3 some keys are bytes object some are str object
- fileName = key.decode('utf-8')
- except:
- pass
-
- # Make sure destination directory exists, ensuring we keep inside dirName
- destName = os.path.join(dirName, fileName.replace("..", "__"))
- destDirName = os.path.dirname(destName)
- if not os.path.exists(destDirName):
- os.makedirs(destDirName)
-
- try:
- data = f.read(length)
- data = zlib.decompress(data)
- except:
- print('[!] Error: Failed to decompress {0}, probably encrypted. Extracting as is.'.format(fileName))
- open(destName + '.pyc.encrypted', 'wb').write(data)
- continue
-
- with open(destName + '.pyc', 'wb') as pycFile:
- pycFile.write(pycHeader) # Write pyc magic
- pycFile.write(b'\0' * 4) # Write timestamp
- if self.pyver >= 33:
- pycFile.write(b'\0' * 4) # Size parameter added in Python 3.3
- pycFile.write(data)
-
-
- def main():
- if len(sys.argv) < 2:
- print('[*] Usage: pyinstxtractor.py <filename>')
-
- else:
- arch = PyInstArchive(sys.argv[1])
- if arch.open():
- if arch.checkFile():
- if arch.getCArchiveInfo():
- arch.parseTOC()
- arch.extractFiles()
- arch.close()
- print('[*] Successfully extracted pyinstaller archive: {0}'.format(sys.argv[1]))
- print('')
- print('You can now use a python decompiler on the pyc files within the extracted directory')
- return
-
- arch.close()
-
-
- if __name__ == '__main__':
- main()
APK本质是一个压缩包,可以修改为.zip然后解压看到里面的内部文件
使用雷电我们是可以直接看到的这些内容
内含:APK安装包名、版本、SDK版本、APP运行权限、Activity主入口函数,第三方SDK调用信息
是我们逆向分析的主要对象是java源码编译生成的java字节文件(是java文件经过jdk编译,再经dex编译生成classes.dex)。可查看域名,IP,加解密算法之类的信息
查看工具:雷电、JEB(看不懂的代码可以使用tab键转换为java语言)、ida等反编译工具
分析方法:先找主程序/入口程序/主函数,然后顺着往下看(合理利用查找)
APK中的证书公钥、有效日期、签名以及证书的MD5、SHA-1/256、指纹信息、数字签名(不同的程序可能名字相同但数字签名不同)
图片,颜色等现在这个文件里面存储,然后在映射道Android的R文件中,形成ID,在使用程序资源是直接就可以通过ID调用
存放第三方库文件,这些so文件一般都是使用C或C++编写,单靠JAVA很难实现高性能,会依赖SO文件,一般一些隐藏的加密文件都会用so文件封装
根据CPU性能架构,lib分为四种分别是ARM(高通骁龙、麒麟基本都是)、ARM-V7、MIPS、x86(桌面笔记本CPU一般使用),对应目录为armeabi、armeabi-v7a、mips、x86
一般越好的程序他的架构越多,能在各种手机上面使用,甚至电脑
通过修该代码函数的名字起到影响查找函数的作用,比如把函数名字改成abcdef什么的
先找主函数,可以找LAUNCHER,LAUNCHER上面那个activity名字就是主函数,然后一步步找主函数页面,找到主函数只有再找oncreate
一般抓包使用https抓包
代理抓包工具(小而美):FIddler、Charles等。可以解密https的,tcp之上的都可以解析
非代理抓包:wireshark、httpdebugger
取证抓包工具:应用程序检测大师系统、雷电
首先下载并配置了flddler的抓包工具
端口写一个不会冲突的端口
然后我们要配置我们的雷电模拟器(注意这里必须要用雷电九,雷电四不能设置WiFi代理)
点击WiFi的齿轮设置手动代理
代理服务器主机名是我们电脑的wife地址
设置完代理之后我们用手机访问就是可以发现是能抓到报的了
确实抓到了
若要解密https流,我们要重新设置
双方都要安装假证书
两者都安装好之后,查看https的官网就可以看到了
这两个图片都有
adb.exe在雷电的文件夹里面,使用要使用cmd
先使用adb devices命令测试链接(出现xxx device表示测试成功可以通讯,不成功可以考虑usb模式是否打开)
在手机上打开要测试的软件程序
adb shell dumpsys window | findstr mCurrentFocus(mCurrentFocus表示鼠标当前光标位置,也就是打开的软件) 获取当前窗口特征,比如包名
adb shell ps 获取进程信息,可以找进程名
adb shell pm path 包名 获取安装路径
adb pull + 路径名,可以讲文件备份拉出来,不指定路径的话就默认存储在雷电文件夹下面
APP安装包: /data/app/目录
APP存储位置: /data/data/目录
有的时候给的不是E01或者DD镜像格式,而是给的vmdk格式的镜像,一般会给你三个:data.vmdk system.vmdk sdcard.vmdk文件,这种用火眼是不能分析的
手机大师解析
模拟器镜像替换解析:在雷电文件夹下的vms文件里面替换
取证大师解析
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。