应用内广告是应用程序开发人员的重要收入来源。
广告商(advertisers):希望对其产品做广告的各方。
发布者(publisher):是给用户带来广告的移动应用(或开发者)。
广告网络或聚合器(Ad networks or aggregators):将发布者与广告商联系起来,由广告商向发布者支付费用。
重定向链(redirection chain):指网页重定向中的URL
登录页面(landing page):指重定向到的最终的网页
广告库(ad library):带有广告的apps中嵌入了广告网络的一些代码,该代码提供了广告网络和发布者(开发人员)之间的纽带,负责管理和投放广告,成为广告库。
Python
实现了大部分系统。AppsPlayground
工具的源代码。【但是该工具的现有版本无法在当前版本的android系统上运行,因此重新实现了该系统,使其能够在当前的android版本上以与AppsPlayground论文中所述相同的探索式方法运行。】UIAutomator
。这对执行速度产生了重大而积极的影响。KVM
加速虚拟化。为此使用可以在x86架构上运行的Android images。大约70%的安卓应用程序没有本机代码(native code),因此可以在这样的目标上正常运行。Celery
来管理的,它为作业管理提供了在分布式环境中部署的能力。Celery
管理的队列中。VirusTotal
扫描文件和URL。Watir
和 Selenium Webdriver
框架在 Chromium web 浏览器上实现了对登陆页面或重定向链中最终URL分析。Watir
和 Webdriver
编写浏览器操作脚本,用于自动加载网页、单击链接、自动下载单击链接时可用的内容,以及在单击链接后加载新页面时返回原始页面。所有的处理都是使用 Xvfb显示服务器
没有任何GUI完成的,该服务器是不显示屏幕输出的X服务器实现。美国部署 | 中国部署 |
---|---|
![]() |
![]() |
美国部署重定向链长度 | 中国部署重定向链长度 |
---|---|
![]() |
![]() |
#!/usr/bin/env python
import sys
import os
import subprocess
import logging
from threading import Thread
# plg是AppsPlayground的库,以下涉及到的代码在后面进行分析
# plg.utils.androidutil包含各种帮助实用程序,用于启动带有“adb”的命令
import plg.utils.androidutil as au
# plg.utils.logcat包含获取“logcat”消息的代码。
import plg.utils.logcat as lc
# plg.metadata从应用程序中提取元数据
# 元数据被定义为:描述数据及其环境的数据
from plg.metadata import getmetadata
# plg.explore.explore提供运行应用程序显示地面的主要入口点
from plg.explore import explore
# plg.settings包含整个代码中使用的各种常量。有些已经不用了。
# 这里:LAUNCHER_PKG = ‘com.android.launcher‘
‘‘‘目前还不知道这个的作用是什么‘‘‘
from plg.settings import LAUNCHER_PKG
# plg.androdevice:带有视图层次结构的连接套接字和 monkey 的 android 设备
# Monkey是运行在模拟器或设备上的一个程序,用来伪随机地模拟点击和触摸等用户事件
# run_monkey():这个monkey设备可以防止进入外部包,还可以检测ANRs(Application Not Responding,应用程序无响应)
from plg.androdevice import run_monkey
MAX_EMULATOR_WAIT = 120 # in seconds
# 终止由启动模拟程序返回的进程
def finish(device):
print(‘killing‘, device, file=sys.stderr)
au.killemulator(device)
# *args 是一个元组tuple(元组与列表类似,不同之处在于元组的元素不能修改)
# 可以接受序列的输入参数。当函数的参数不确定时,可以使用 *args
def main(avd, app, *args):
emu_cmd = [‘emulator64-x86‘, ‘@{}‘.format(avd)] #启动模拟器的命令
# 如果输入在args中的前两个元素是:-system filepath
# 这个是用来指定初始系统文件。提供文件名,以及绝对路径或相对于工作目录的路径
# 如果不使用此选项,则默认为系统目录中的 system.img 文件
if args and args[0] == ‘-system‘:
emu_cmd.extend(args[:2]) # 顾头不顾尾,取前两个元素放到emu_cmd列表后
args = args[2:] # args中第三个元素一直到最后重新赋值给args元组
#对于计算机上运行的第一个虚拟设备实例,默认值为 5554
# 在特定计算机上运行的第一个虚拟设备的控制台使用控制台端口 5554 和 adb 端口 5555。
# 后续实例使用的端口号渐增 2,例如 5556/5557、5558/5559 等。
# 范围是 5554 到 5682,可用于 64 个并发虚拟设备。
port = 5554
# 如果args内容不为空,就把args的第一个值赋给port,之后的给 *args
if args:
port, *args = args
log = ‘log.txt‘
# 如果args内容不为空,就把args的第一个值赋给log,之后的给 *args
if args:
log, *args = args # we will ignore other args
#启动模拟器的命令;
#extend()函数用于在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
#-no-snapshot-save:执行快速启动,但在退出时不保存模拟器状态
#-port:设置用于控制台和 adb 的 TCP 端口号
#-m 512:是给客户机分配 512MB 内存
#-enable-kvm:利用 KVM 来访问硬件提供的虚拟化服务
emu_cmd.extend([‘-no-snapshot-save‘, ‘-port‘, str(port), ‘-qemu‘, ‘-m‘,
‘512‘, ‘-enable-kvm‘])
# the x86 emulators need help finding some libraries
# environ 是一个字符串所对应环境的映像对象
#把 android-sdk/tools/lib 添加到 LD_LIBRARY_PATH 路径中
emu_env = os.environ.copy()
emu_env[‘LD_LIBRARY_PATH‘] = (‘/home/ubuntu/Android/sdk/‘
‘tools/lib‘)
device = ‘emulator-{}‘.format(port)
au.init() # 杀死当前存在的模拟器
# file=sys.stderr:将当前默认的错误输出结果保存为 file
print(‘launching‘, device, file=sys.stderr)
# subprocess.Popen 类来处理基本的进程创建和管理
# 开始执行命令
subprocess.Popen(emu_cmd, env=emu_env)
‘‘‘ Python的异常处理机制的语法结构:
try:
<语句>
except <name>:
<语句> #如果在try部份引发了名为‘name‘的异常,则执行这段代码
else:
<语句> #如果没有异常发生,则执行这段代码
‘‘‘
try:
# 等待设备上线
au.waitfordevice(device, timeout=MAX_EMULATOR_WAIT)
except subprocess.TimeoutExpired:
# 保留一个“timeout”用于错误处理
# 当想要自己的模拟器启动,它实际上可能并没有启动
print(‘time out expired while waiting for‘, device, file=sys.stderr)
raise # 该语句引发当前上下文中捕获的异常
# 从 time 模块中引入sleep函数
# 使用sleep函数可以让程序休眠(推迟调用线程的运行)
from time import sleep
#sleep(300) # 休眠300秒
# getadbcmd():帮助函数,返回命令 adb -s emulator-5554 install app
# 这个命令的意思是:在emulator-5554模拟器上安装app(.apk)
install_cmd = au.getadbcmd([‘install‘, app], device)
try:
# 子进程执行install_cmd中的命令,并将其输出形成字符串返回
# 如果子进程退出码不是0,抛出subprocess.CalledProcessError异常
# 将stderr参数设置为subprocess.STDOUT,表示将错误通过标准输出流输出
subprocess.check_output(install_cmd, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
# join():用于将序列中的元素以指定的字符(这里应该是空格)连接生成一个新的字符串
# splitlines():按行分割字符串,返回值是个列表
info = ‘install-failed ret:%d %s‘ % (e.returncode,
b‘ ‘.join(e.output.splitlines()))
print(‘info‘, file=sys.stderr)
finish(device) # 终止由启动模拟程序返回的进程
# config logcat配置日志
lc_file = log
# 执行命令:adb -s emulator -5554 logcat -c
# -c:清除屏幕上的日志
lc.clearlogcat(device)
#
lc.logcat(lc_file, device) # file open/close is done by callee
# 从应用程序中提取元数据
metainfo = getmetadata(app)
# launch monkey to prevent straying and deal with ANRs
# 触发monkey来防止走失和避免ANRs
‘‘‘ 使用Thread类实现多线程:
1、创建Thread类的实例;
2、通过Thread类的构造方法的target关键字参数执行线程函数;通过args关键字参数指定传给线程函数的参数。
3、调用Thread对象的start方法启动线程。
其中:
target: 要执行的方法
args: 要传入方法的参数
‘‘‘
# 这里run_monkey()执行的命令是:adb -s emulator-5554 shell monkey --port 1080 -p metainfo[‘name‘]
# --port 端口号:为测试分配一个专用的端口号
# -p:用此参数指定一个或多个包(Package,即App)。指定包之后,monkey将只允许系统启动指定的APP,如果不指定包,将允许系统启动设备中的所有APP.
# 该命令的意思是:在emulator-5554模拟器上,启动指定的应用程序
t = Thread(target=run_monkey, args=(device, metainfo[‘name‘]))
t.daemon = True #daemon被设置为True时,如果主线程退出,那么子线程也将跟着退出
t.start() #启动线程
print(‘begin exploring‘)
# explore():AppsPlayground的主要入口点
explore(device, metainfo)
print(‘finish exploring‘)
finish(device) # 终止由启动模拟程序返回的进程
if __name__ == ‘__main__‘:
# 输入的参数中不能有 help、-h、-help
if (‘help‘ in sys.argv or ‘-h‘ in sys.argv or ‘-help‘ in sys.argv or
len(sys.argv) < 3):
print(‘usage:‘, sys.argv[0],
‘avd app [-system <system.img>] [port [log]]‘)
#sys.exit(0):表示正常退出
#sys.exit(2):数值2为不正常,可抛异常事件供捕获
sys.exit(2 if len(sys.argv) < 3 else 0)
# logging 模块用于打印日志
# logging.basicConfig()函数实现打印日志的基础配置
# 参数level: 设置日志级别,默认为logging.WARNING
# 参数stream: 指定日志的输出流,默认输出到sys.stderr
logging.basicConfig(level=logging.WARNING, stream=sys.stderr)
# 将输入的参数传入到main函数
main(*sys.argv[1:])
# 杀死任何已存在的模拟器
def init(logfile=None):
if not logfile:
logfile = sys.stderr # 将当前默认的错误输出结果保存为logfile
print(‘(re)starting adb server‘, file=logfile)
killserver()
startserver()
#sleep(10) # let adb start
print(‘killing any emulators already present‘, file=logfile)
for device in getdevices():
killemulator(device)
def getadbcmd(args=None, device=None):
‘‘‘ helper function:
args - arguments excluding adb and device‘‘‘
preargs = [ADB]
if device:
#strip()方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
device = device.strip()
if device:
preargs += [‘-s‘, device]
if not args:
return preargs
return preargs + args
def runadbcmd(args, device=None):
# 运行由args参数提供的命令
# 如果命令行执行成功,check_call返回返回码 0
# 否则抛出subprocess.CalledProcessError异常
return subprocess.check_call(getadbcmd(args, device))
def clearlogcat(device=None):
return androidutil.runadbcmd([‘logcat‘, ‘-c‘], device)
def _enqueue_output(out, q):
for line in iter(out.readline, b‘‘):
q.put(line)
out.close()
def logcatlines(device=None, args=‘‘):
# cmd的值是:adb -s emulator-5554 logcat
# 该命令的意思是:查看日志输出
cmd = ‘ ‘.join(androidutil.getadbcmd(args, device)) + ‘ logcat ‘ +args
‘‘‘
这里使用了pty模块,pty模块定义了处理伪终端概念的操作:启动另一个进程,并能够以编程方式读写其控制终端。
因为伪终端处理是高度依赖于平台的,所以只有在Linux下才有代码可以做到这一点。
pty.openpty():
Open a new pseudo-terminal pair, using os.openpty() if possible,
or emulation code for generic Unix systems. Return a pair of file
descriptors (master, slave), for the master and the slave end, respectively.
打开一个新的伪终端对,分别为主机和从机端返回一对文件描述符(主机、从机)。
‘‘‘
logmaster, logslave = pty.openpty()
# subprocess模块中的Popen类来创建进程,并与进程进行复杂的交互
# 参数stdout, stderr分别表示子程序的标准输出、错误句柄。
# 参数shell设为True,指定的命令会在shell里解释执行
# 参数close_fds设为True,执行新进程前把除了0、1、2以外的文件描述符都先关闭
logcatp = subprocess.Popen(cmd, shell=True,
stdout=logslave, stderr=logslave, close_fds=True)
# os.fdopen()方法:用于通过文件描述符 fd 创建一个文件对象,并返回这个文件对象
# 这里logmaster文件描述符是一个小整数
stdout = os.fdopen(logmaster)
q = Queue()
t = Thread(target=_enqueue_output, args=(stdout, q))
t.daemon = True
t.start()
while logcatp.poll() is None:
try:
yield q.get(True, 1)
except Empty:
continue
def _logcat(device, fname, logcatargs):
with open(fname, ‘w‘) as f:
for line in logcatlines(device, logcatargs):
f.write(line)
f.flush()
def logcat(fname, device=None, logcatargs=‘‘):
‘‘‘ run logcat and collect output in file fname.‘‘‘
# 通过Process类创建进程,基本使用与 Thread() 类似
proc = Process(target=_logcat, args=(device, fname, logcatargs))
proc.start()
# 从应用程序中提取元数据
def getmetadata(apk):
# 在子进程执行命令,以字符串形式返回执行结果的输出
# 如果子进程退出码不是0,抛出subprocess.CalledProcessError异常
# 执行的命令是:aapt d badging apk,用来查看apk版本及其相关信息
aaptout = subprocess.check_output([‘aapt‘, ‘d‘, ‘badging‘, apk])
# 创建了一个存放元数据的字典
data = {}
data[‘uses-permission‘] = []
data[‘uses-feature‘] = []
data[‘uses-library‘] = []
data[‘launchable‘] = []
# splitlines():按照行(‘\r‘, ‘\r\n‘, \n‘)分隔,返回一个包含各行作为元素的列表
# 这里没有参数,相当于keepends为 False,不包含换行符
# 直接对file对象使用for循环读每行数据
for line in aaptout.splitlines():
line = line.decode() # 解码(将字节码转换为字符串,将比特位显示成字符)
# split():通过指定分隔符 ‘ 来对字符串进行切片
tokens = line.split("‘")
# startswith():用于检查字符串是否是以指定子字符串开头,如果是则返回 True,否则返回 False
if line.startswith(‘package:‘):
data[‘name‘] = tokens[1]
data[‘versionCode‘] = tokens[3]
data[‘versionName‘] = tokens[5]
elif line.startswith(‘uses-permission‘):
data[‘uses-permission‘].append(tokens[1])
elif line.startswith(‘sdkVersion‘):
data[‘sdkVersion‘] = tokens[1]
elif line.startswith(‘targetSdkVersion‘):
data[‘targetSdkVersion‘] = tokens[1]
elif line.startswith(‘uses-feature‘): # both required and not required
data[‘uses-feature‘].append(tokens[1])
elif line.startswith(‘uses-library‘): # both required and not required
data[‘uses-library‘].append(tokens[1])
elif line.startswith(‘application:‘):
data[‘app-label‘] = tokens[1]
data[‘app-icon‘] = tokens[3]
elif line.startswith(‘launchable activity‘) or line.startswith(
‘launchable-activity‘):
data[‘launchable‘].append(dict(name=tokens[1],
label=tokens[3], icon=tokens[5]))
return data
def run_monkey(name=None, pkg=None):
‘‘‘
This monkey process prevents going to outside packages and also detects
ANRs. In future we may do something else for these two functionalities. In
case of ANR, kill emulator so that this worker eventually crashes.
Parameters
----------
name: str
the device name such as ‘emulator-5554‘
pkg: str
the application package outside which plg should not go
‘‘‘
cmd = [‘shell‘, ‘monkey‘, ‘--port‘, ‘1080‘]
if pkg:
cmd.extend([‘-p‘, pkg])
runadbcmd(cmd, name)
killemulator(name)
def explore(dev, appinfo):
‘‘‘ The main entrypoint for AppsPlayground.
Parameters
----------
dev:
can be a string like ‘emulator-5554‘ or an `AndroidDevice` instance
appinfo:
the metadata for the app, such as one derived from
plg.metadata.getmetadata()
‘‘‘
if type(dev) is AndroidDevice:
androdev = dev
dev = dev.name
else:
dev = str(dev)
androdev = AndroidDevice(dev)
DevState(dev, androdev, appinfo).explore()
jdk-8u241-linux-x64.tar.gz
进行解压sudo tar zxvf ./jdk-8u241-linux-x64.tar.gz
sudo vim /etc/profile
#set Java environment
export JAVA_HOME=/home/ubuntu/jdk1.8.0_241
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
source /etc/profile
java -version
检查Java是否已经安装在Ubuntu上sh /home/ubuntu/android-studio/bin/studio.sh
sudo vim /etc/profile
export ANDROID_HOME=/root/Android/Sdk
export PATH=${PATH}:${ANDROID_HOME}/tools
export PATH=${PATH}:${ANDROID_HOME}/platform-tools
export PATH=${PATH}:${ANDROID_HOME}/build-tools
source /etc/profile
android -h
和 adb
What‘s KVM?
KVM实际是linux内核提供的虚拟化架构,可将内核直接充当hypervisor来使用。KVM需要处理器硬件本身支持虚拟化扩展,如intel VT 和AMD AMD-V技术。KVM自2.6.20版本后已合入主干并发行,除此之外,还以模块形式被移植到FreeBSD和illumos中。除了支持x86的处理器,同时也支持S/390,PowerPC,IA-61以及ARM等平台。
工作原理
KVM包含一个内核模块kvm.ko用来实现核心虚拟化功能,以及一个和处理器强相关的模块如kvm-intel.ko或kvm-amd.ko。KVM本身不实现任何模拟,仅仅是暴露了一个/dev/kvm接口,这个接口可被宿主机用来主要负责vCPU的创建,虚拟内存的地址空间分配,vCPU寄存器的读写以及vCPU的运行。有了KVM以后,guest os的CPU指令不用再经过QEMU来转译便可直接运行,大大提高了运行速度。但KVM的kvm.ko本身只提供了CPU和内存的虚拟化,所以它必须结合QEMU才能构成一个完整的虚拟化技术。
What‘s QEMU-KVM?
QEMU-KVM,是QEMU的一个特定于KVM加速模块的分支,里面包含了很多关于KVM的特定代码,与KVM模块一起配合使用。
目前QEMU-KVM已经与QEMU合二为一,所有特定于KVM的代码也都合入了QEMU,当需要与KVM模块配合使用的时候,只需要在QEMU命令行加上 --enable-kvm就可以。
egrep -c ‘(vmx|svm)‘ /proc/cpuinfo
sudo apt-get update
一下,然后安装KVM依赖:sudo apt-get install qemu-kvm
sudo apt-get install qemu
sudo apt-get install virt-manager
sudo apt-get install virt-viewer
sudo apt-get install libvirt-bin
sudo apt-get install bridge-utils
kvm-ok
,出现下面的界面,就说明已经装好了sudo virt-manager
,可以进入图形界面。sudo adduser xxx kvm
sudo adduser xxx libvirtd
virsh list --all
aapt 为 Android Asset Packaging Tool , 在SDK的build-tools/目录下. 该工具可以查看, 创建, 更新ZIP格式的文档附件(zip, jar, apk). 也可将资源文件编译成二进制文件。
sudo vim /etc/profile
# Add Android build-tools AAPT variable
export AAPT_HOME=/root/Android/Sdk/build-tools/29.0.3
export AAPT_HOME
export PATH=$PATH:$AAPT_HOME
source /etc/profile
aapt
检查:android-sdk/tools/lib
to LD_LIBRARY_PATH
.sudo vim /etc/profile
,添加export LD_LIBRARY_PATH=/root/Android/Sdk/tools/lib:$LD_LIBRARY_PATH
source /etc/profile
echo $LD_LIBRARY_PATH
即会显示:在命令行使用命令 android sdk
打开 Android SDK Manager
,然后选择安装ABI,注意:下载时必须下载带有system image的项目,不然创建AVD时就会报如下的错误。参考
添加之后可以运行啦!
运行的过程中会出现类似以下这样的问题,我就照着在相应的位置(运行卡住的模块后面)添加对应的模块,一共添加了如下九个模块(猜测可能是因为修改了android的平台版本编号导致)。
使用命令 android list avd
查看新创建的AVD,发现错误:
查了好多资料,说这个问题的原因是Android Studio安装和Sdk的安装位置不在同一个盘符下面,还有就是ANDROID_AVD_HOME这个环境变量要是SDK目录,然后我修改了环境变量,整体的环境变量如下:
然鹅。。不行。。。。
创建过程中出现的问题如下,发现有很多 EOF 和 TIMEOUT 的字样,查阅资料,分析异常:
TIMEOUT 异常:如果子程序没有在指定的时间内生成任何 output,那么 expect()
和 read()
都会产生 TIMEOUT 异常。超时默认是 30s,可以在 expect()
和 spawn
构造函数初始化时指定为其它时间。若想让 expect()
和 read()
忽略超时限制,即无限期阻塞住直到有 output 产生,设置 timeout 参数为 None。
原来的代码如下:
p = pexpect.spawn(‘android create avd -n {} -t android-17 --snapshot‘
‘ --sdcard 200M --abi x86‘.format(sys.argv[1]), timeout=2)
emulator64-x86 -avd y -no-snapshot-load -qemu -m 512 -enable-kvm
命令行选项 | 说明 |
---|---|
-no-snapshot-load | 阻止模拟器从快照存储加载 AVD 状态。执行完整启动。执行冷启动,并在退出时保存模拟器状态。 |
-no-snapshot-save | 如果可能,执行快速启动,但在退出时不保存模拟器状态。也就是阻止模拟器在退出时将 AVD 状态保存到快照存储,这意味着所有更改都将丢失。 |
-m 512 | 是给客户机分配512MB内存 |
-enable-kvm | 利用 KVM 来访问硬件提供的虚拟化服务 |
pip
安装需要的模块的时候,出现下面这样的问题:you are using pip version 10.0.1,however version 20.0.2 is available
You should consider upgrading via the ‘pip install --upgrade pip’ command.
pip install --upgrade pip --user
ERROR: requests 2.19.1 has requirement urllib3<1.24,>=1.21.1, but you‘ll have urllib3 1.9 which is incompatible.
/home/ubuntu/anaconda3/lib/python3.7/site-packages/requests/__init__.py:91: RequestsDependencyWarning: urllib3 (1.9) or chardet (3.0.4) doesn‘t match a supported version!
RequestsDependencyWarning)
pip install --upgrade urllib3
pip install --upgrade requests
后来又遇到下面问题,重新安装pycharm即可。
我发现在命令行使用命令 pip list
显示所安装好的包之后,在pycharm的解释器环境中找不到对应安装好的包,使用命令 which python
查看ubuntu中安装的python路径,然后就可以找到在命令行安装好的包啦。
Ctrl + Alt + PrtSc (SysRq) + reisub
,再说明白一点,就是按住Ctrl,Alt和PtrSc(SysRq),按住他们的同时你需要按r,e,i,s,u,b 这样就能安全地重启linux/usr/bin/sudo vim /etc/profile (由于找不到sudo,所以必须写全路径,其他命令如果提示找不到,也需要写全路径)
export PATH="$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
source /etc/profile
20199324 2019-2020-2 《网络攻防实践》综合实践
原文:https://www.cnblogs.com/yangdd/p/13222368.html