"""
APK功能与布局分析脚本
分析Via浏览器的功能点和布局交互
"""
import os
import sys
import json
import zipfile
import xml.etree.ElementTree as ET
from pathlib import Path
import re
APK_PATH = r"C:\Users\CYT\Desktop\base.apk"
OUTPUT_DIR = r"C:\Users\CYT\DevEcoStudioProjects\GlanceBrowser\apk_analysis"
def create_output_dir():
"""创建输出目录"""
os.makedirs(OUTPUT_DIR, exist_ok=True)
os.makedirs(os.path.join(OUTPUT_DIR, 'resources'), exist_ok=True)
os.makedirs(os.path.join(OUTPUT_DIR, 'smali'), exist_ok=True)
os.makedirs(os.path.join(OUTPUT_DIR, 'analysis'), exist_ok=True)
def extract_apk():
"""解压APK文件"""
print(f"正在解压APK: {APK_PATH}")
with zipfile.ZipFile(APK_PATH, 'r') as zip_ref:
if 'AndroidManifest.xml' in zip_ref.namelist():
zip_ref.extract('AndroidManifest.xml', OUTPUT_DIR)
for file in zip_ref.namelist():
if file.startswith('res/') and file.endswith('.xml'):
try:
zip_ref.extract(file, OUTPUT_DIR)
except:
pass
for file in zip_ref.namelist():
if file.endswith('.dex'):
zip_ref.extract(file, OUTPUT_DIR)
for file in zip_ref.namelist():
if 'layout' in file and file.endswith('.xml'):
try:
zip_ref.extract(file, OUTPUT_DIR)
except:
pass
print(f"APK解压完成,输出目录: {OUTPUT_DIR}")
def analyze_manifest():
"""分析AndroidManifest.xml"""
manifest_path = os.path.join(OUTPUT_DIR, 'AndroidManifest.xml')
if not os.path.exists(manifest_path):
print("未找到AndroidManifest.xml")
return None
print("分析AndroidManifest.xml...")
with open(manifest_path, 'rb') as f:
content = f.read()
manifest_info = {
'permissions': [],
'activities': [],
'services': [],
'receivers': []
}
content_str = content.decode('latin-1')
permissions = re.findall(r'android\.permission\.([A-Z_]+)', content_str)
manifest_info['permissions'] = list(set(permissions))
activities = re.findall(r'([a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)*)Activity', content_str)
manifest_info['activities'] = list(set(activities))[:20]
return manifest_info
def analyze_layouts():
"""分析布局文件"""
layout_dir = os.path.join(OUTPUT_DIR, 'res')
if not os.path.exists(layout_dir):
print("未找到资源目录")
return []
layouts = []
for root, dirs, files in os.walk(layout_dir):
for file in files:
if 'layout' in root and file.endswith('.xml'):
layout_path = os.path.join(root, file)
layout_name = os.path.basename(root) + '/' + file
try:
with open(layout_path, 'rb') as f:
content = f.read()
content_str = content.decode('latin-1', errors='ignore')
components = []
if 'EditText' in content_str:
components.append('EditText')
if 'Button' in content_str:
components.append('Button')
if 'ImageView' in content_str:
components.append('ImageView')
if 'TextView' in content_str:
components.append('TextView')
if 'RecyclerView' in content_str:
components.append('RecyclerView')
if 'ListView' in content_str:
components.append('ListView')
if 'WebView' in content_str:
components.append('WebView')
if 'Toolbar' in content_str:
components.append('Toolbar')
if 'BottomNavigationView' in content_str:
components.append('BottomNavigationView')
if 'DrawerLayout' in content_str:
components.append('DrawerLayout')
if 'CoordinatorLayout' in content_str:
components.append('CoordinatorLayout')
if 'AppBarLayout' in content_str:
components.append('AppBarLayout')
if 'SwipeRefreshLayout' in content_str:
components.append('SwipeRefreshLayout')
if 'ProgressBar' in content_str:
components.append('ProgressBar')
if 'SearchView' in content_str:
components.append('SearchView')
if 'FloatingActionButton' in content_str:
components.append('FloatingActionButton')
if 'CardView' in content_str:
components.append('CardView')
if 'TabLayout' in content_str:
components.append('TabLayout')
if 'ViewPager' in content_str:
components.append('ViewPager')
layouts.append({
'name': layout_name,
'components': components,
'size': len(content)
})
except Exception as e:
pass
return layouts
def analyze_resources():
"""分析资源文件"""
res_dir = os.path.join(OUTPUT_DIR, 'res')
if not os.path.exists(res_dir):
return {}
resources = {
'drawables': 0,
'layouts': 0,
'values': 0,
'menus': 0,
'strings': 0
}
for root, dirs, files in os.walk(res_dir):
for file in files:
if 'drawable' in root:
resources['drawables'] += 1
elif 'layout' in root:
resources['layouts'] += 1
elif 'values' in root:
resources['values'] += 1
elif 'menu' in root:
resources['menus'] += 1
elif 'string' in file:
resources['strings'] += 1
return resources
def analyze_dex():
"""分析DEX文件(简单分析)"""
dex_files = []
for file in os.listdir(OUTPUT_DIR):
if file.endswith('.dex'):
dex_path = os.path.join(OUTPUT_DIR, file)
dex_size = os.path.getsize(dex_path)
with open(dex_path, 'rb') as f:
content = f.read()
content_str = content.decode('latin-1', errors='ignore')
key_classes = []
if 'WebView' in content_str:
key_classes.append('WebView')
if 'WebChromeClient' in content_str:
key_classes.append('WebChromeClient')
if 'WebViewClient' in content_str:
key_classes.append('WebViewClient')
if 'Activity' in content_str:
key_classes.append('Activity')
if 'Fragment' in content_str:
key_classes.append('Fragment')
if 'Adapter' in content_str:
key_classes.append('Adapter')
if 'Bookmark' in content_str:
key_classes.append('Bookmark')
if 'History' in content_str:
key_classes.append('History')
if 'Download' in content_str:
key_classes.append('Download')
if 'Settings' in content_str:
key_classes.append('Settings')
if 'AdBlock' in content_str or 'AdBlocker' in content_str:
key_classes.append('AdBlock')
if 'Theme' in content_str:
key_classes.append('Theme')
if 'NightMode' in content_str:
key_classes.append('NightMode')
if 'ReaderMode' in content_str:
key_classes.append('ReaderMode')
if 'FindInPage' in content_str:
key_classes.append('FindInPage')
if 'TabManager' in content_str:
key_classes.append('TabManager')
dex_files.append({
'name': file,
'size': dex_size,
'key_classes': list(set(key_classes))
})
return dex_files
def generate_analysis_report():
"""生成分析报告"""
print("\n" + "="*60)
print("Via浏览器APK功能与布局分析报告")
print("="*60)
manifest_info = analyze_manifest()
layouts = analyze_layouts()
resources = analyze_resources()
dex_info = analyze_dex()
report = {
'apk_path': APK_PATH,
'manifest': manifest_info,
'layouts': layouts,
'resources': resources,
'dex_info': dex_info,
'analysis_time': str(os.path.getmtime(APK_PATH))
}
report_path = os.path.join(OUTPUT_DIR, 'analysis', 'apk_analysis.json')
with open(report_path, 'w', encoding='utf-8') as f:
json.dump(report, f, indent=2, ensure_ascii=False)
print(f"\n分析报告已保存: {report_path}")
print("\n【功能摘要】")
print(f"- 权限数量: {len(manifest_info['permissions']) if manifest_info else 0}")
print(f"- 布局文件数: {len(layouts)}")
print(f"- 资源统计: {resources}")
print(f"- DEX文件数: {len(dex_info)}")
if dex_info:
print("\n【关键功能类】")
all_classes = set()
for dex in dex_info:
all_classes.update(dex['key_classes'])
print(f"- {', '.join(sorted(all_classes))}")
print("\n【布局组件统计】")
component_count = {}
for layout in layouts:
for comp in layout['components']:
component_count[comp] = component_count.get(comp, 0) + 1
for comp, count in sorted(component_count.items(), key=lambda x: x[1], reverse=True):
print(f"- {comp}: {count}次")
return report
def main():
"""主函数"""
print("开始分析Via浏览器APK...")
if not os.path.exists(APK_PATH):
print(f"错误: APK文件不存在: {APK_PATH}")
return
create_output_dir()
extract_apk()
report = generate_analysis_report()
print("\n分析完成!")
if __name__ == '__main__':
main()