欢迎光临!欢迎分享转载本站文章,尊重原创,转载请注明出处!

Android应用商店apk下载重定向测试

2017年6月24日 没有评论

首先声明:本文仅用于学习测试,不进行任何目的的实际应用,请勿用作非法目的!

服务器对下载的处理一般有3种方法:

  • 直接返回下载文件内容
  • 进行简单校验,将下载请求302重定向至下载文件
  • 进行简单校验,通过200返回下载URL和校验数据,客户端将文件下载完成后再次进行校验

目前大部分应用商店是通过第三种方法处理apk下载的,这样可以初步避免客户端发起的下载请求被重定向。但只要数据是通过http协议进行传输的,都不能完全避免被重定向。

比如,返回给客户端的校验数据也是可以被抓包工具捕获的,这样就提供了被修改的可能。经过认真分析比对下载过程,可以修改下载URL和校验数据,让手机应用商店下载修改后的URL,并使用伪校验数据来校验。这样就有可能将apk重定向至非法应用!

我们测试了一款appstore,发现它的下载过程分三步:

  • appstore发起下载请求,服务器通过200返回下载URL和校验数据
  • appstore再次发起下载请求,服务器通过302返回真正的下载地址
  • appstore第三次发起下载请求,下载apk后进行校验
  • 校验内容包括但不限于:文件名称、大小、md5、版本

测试过程中遇到一些问题及对应的解决办法

  • 测试环境不佳,只能在重定向服务器所在的网段内能100%捕获到下载请求:在重定向服务器上搭建nginx透明代理,将测试客户端上特定的域名解析到代理服务器
  • 使用Android模拟器测试无效果,没有办法解析域名,无法捕获到下载请求:使用真机测试
  • 在手机上下载应用商店,修改手机上的hosts文件,可以捕获到下载请求
  • 不同APP下载后无法进行安装:只能进行同一APP的下载重定向。

由于各应用商店厂商也在不断做安全调整,所以需要实时跟踪下载协议,更新重定向策略。

本文亦提醒应用商店厂商及时调整下载策略,避免流量损失。

分类: 开发 标签: ,

使用mongoexport导出某个时间段内的数据

2017年6月24日 没有评论

mongoexport是MongoDB自带一个数据导出工具,可以方便的导出查询结果。现通过一条命令来演示使用方法,特别是如何查询某个时间段内的数据。

数据库名称:testDB

集合名称:testColl

查询条件:2017-06-12当天的所有记录

导出列:userId, userName

导出文件类型:csv,不含“表头”

./mongoexport –db testDB –collection testColl –query='{“time”:{$gte:ISODate(“2017-06-12T00:00:00Z”)}, “time”:{$lt:ISODate(“2017-06-13T00:00:00Z”)}}’ –fields=”userId,userName” –type=”csv” –noHeaderLine –out results

请注意加粗参数的用法。

–query:指定查询条件,多个条件可以进行and或or的逻辑组合。此处组合了起止时间。

–fields:指定输出字段,默认输出全部字段

–noHeaderLine:不输出字段名称

官方文档指出:export不适于用作生产环境的全库数据备份,请使用mongodump进行全库备份。

分类: MongoDB 标签:

多网卡环境下VMware虚拟机桥接宿主机网络不通的解决办法

2017年5月22日 没有评论

如题所述,一般都是在个人电脑上安装VMwareWorkStation,然后装几个虚拟机进行测试。自己的电脑一般都是一个网卡,直接将虚拟机桥接到物理网卡上就行了,无须过多设置。

今天在一台Windows服务器上装了一个VMwareWorkStation,通过桥接将虚拟机连上宿主机后,网络一直不通。

service network restart命令提示网线未接入或者网卡设备未激活之类的信息,但宿主机明明是可以上网的。搜了好久终于找到原因和解决办法:

  • 宿主机上有多块网卡,只有一个网卡插入了网线
  • VMware桥接选项默认自动选择了一块网卡,恰好不是可以上网的网卡

这种情况下,需要手动编辑虚拟网络,步骤如下:

  • VMware菜单中选择“编辑”->“虚拟网络编辑器”,打开虚拟网络编辑器
  • 选中“VMnet0”,如果看不到“VMnet0”可以通过“添加网络”手动将VMnet0添加进来
  • 在下边的“桥接模式”中,通过下拉选择可以联网的网卡,保存设置
  • 重启虚拟机网络
分类: 资料 标签:

wtail:可以多屏输出的多文件跟踪查看工具

2017年5月17日 没有评论

tail是我们常用到的文件跟踪查看工具,-n可以查看末尾n行,-f可以实时跟踪文件(描述符)的最新变化。当然也可以同时查看多个文件,但是多文件的输出是混杂在一起的,没那么直观。

现在好了,我们有了wtail。这是一个可以在同一个终端窗口中同时输出多个被跟踪文件数据的工具,每个文件可以在单独的小屏幕中输出,即一个窗口分屏输出。

  1. 安装
    • wtail依赖libncurses,某些机器上可能没有这个库,需要手动安装:

      wget http://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.0.tar.gz

      tar xzvf ncurses-6.0.tar.gz && cd ncurses-6.0

      ./configure && make && make install

    • 下载wtail源码包,解压,make && make install
  2. 使用
    • wtail *.log
分类: Shell, 工具, 运维 标签: , ,

低版本Java会导致APKTool解析apk包时产生异常

2017年5月8日 没有评论

通过java -jar apktool_2.2.2.jar d -s -f a.apk解析apk包时产生一个异常报错:

Exception in thread “main” java.lang.ClassFormatError: brut.apktool.Main (unrecognized class file version)
at java.lang.VMClassLoader.defineClass(libgcj.so.10)
at java.lang.ClassLoader.defineClass(libgcj.so.10)
at java.security.SecureClassLoader.defineClass(libgcj.so.10)
at java.net.URLClassLoader.findClass(libgcj.so.10)
at java.lang.ClassLoader.loadClass(libgcj.so.10)
at java.lang.ClassLoader.loadClass(libgcj.so.10)
at gnu.java.lang.MainThread.run(libgcj.so.10)

在stackoverflow.com上找到了问题的原因:执行解析的服务器上安装的Java版本较低

so,更新Java到最新版本,重新执行,问题解决。

分类: 开发 标签: ,

使用rsync进行文件同步

2017年4月25日 没有评论
  1. rysnc是什么
    1. 这是一个linux平台上通用的文件同步工具,可以在本地目录或本地与服务器之间进行文件同步
    2. 安全:支持自定义端口,支持口令配置
    3. 高效:只传输差异部分,支持压缩传输
    4. 易用:支持通配符,支持exclude来排除特定文件
  2. 安装
    1. 大多数linux服务器默认安装有rsync
    2. 如果没有,简单运行yum -y install rsync就ok了
  3. 简单示例
    1. 同步的前提是两端服务器都安装了rsync
    2. push方式:rsync /localDir/file user@remoteServerAddress:/remoteDir
    3. pull方式:rsync user@remoteServerAddress:/remoteDir/file /localDir
    4. 上述两条命令实际上是通过ssh来通信的,所以如果对端服务器用户配置了密码的话需要输入密码
    5. rsync还支持通过rync协议来通信,有两种命令方式可以使用该协议
      1. 在服务器和路径之间使用双冒号,比如

        rsync /localDir/file user@remoteServerAddress::/remoteDir

      2. 显式使用,如

        rsync rsync://user@remoteServerAddress[:remoteServerPort]/remoteDir/file /localDir

  4. 以daemon方式配置和运行
    1. rsync可以在一端或者两端以daemon进程形式来运行,通过配置rsyncd.conf来定制同步业务
    2. 这里列举一个简单的配置文件/etc/rsyncd.conf:

      #global settings
      pid file = /var/rsync/rsync.pid
      port = 873
      lock file = /var/rsync/lock.log
      log file = /var/rsync/rsync.log

      #module settings
      [SyncFiles]
      path=/data/files/
      use chroot = no
      max connections = 5
      read only = yes
      write only = no
      list = no
      uid = nobody
      gid = nobody
      incoming chmod = 644
      auth users = syncUser
      secrets file = /etc/rsync.pass
      strict modes = yes
      hosts allow = 192.168.1.119
      hosts deny = *
      ignore errors = yes
      timeout = 120

    3. 授权文件/etc/rsync.pass格式

      syncUser:_password_

    4. 注意事项:需要chmod 600 /etc/rsync.pass
    5. 启动进程:rsync –daemon,可将此命令加入/etc/rc.local
    6. 客户端同步命令:

      rsync -az –password-file=./sync_auth rsync://syncUser@remoteServerAddress[:remoteServerPort]/SyncFiles/* /localDir

    7. 由于同步用户配置了权限,客户端每次rsync操作都需要输入密码,可以通过–password-file选项来指定密码文件,这样就可免去输入密码了,如上面命令所示。该密码文件的格式很简单,单行文本写入密码即可,同样需要chmod 600 ./sync_auth
  5. 检测文件是否需要同步
    1. -i参数:可以对对端文件的变更进行摘要,据此可以判断是否需要同步
    2. -n参数:尝试同步操作但不传输文件
    3. 结合起来,-in就可以根据输出来判断是否需要同步了
  6. 其他:
    1. –delete参数支持删除文件的同步
    2. -L支持软链接目标目录的同步
    3. 如果写入的目录没有权限,会报以下错误,执行chown -R nobody.nobody /data/files/修改权限即可解决

      rsync: mkstemp failed: Permission denied (13)

分类: Shell, 运维 标签: , , ,

扑克洗牌算法(c++版)

2017年3月20日 没有评论

这是三年前去一家游戏公司面试时被问到的一个问题,当时由于自己在传统软件公司做业务,对算法没有留心学习,虽勉强答出来了,但从未实现过。今天随手写了个小程序做下验证。

基本思路:将代表扑克牌的52个数字放入vector中,每次随机抽取一张放入新的vector,并将被抽取牌从原vector中删除。如此循环52次,即可得到随机化的牌面。

代码如下:

#include <iostream>
using namespace std;
#include <vector>
#include <stdlib.h>

int main()
{
unsigned int total;
cout << “Please input the TOTAL:” << endl;  //输入52
cin >> total;

//将52个数放入vCards0

vector<unsigned int> vCards0;
unsigned int i=1;
while(i <= total)
{
vCards0.push_back(i++);
}

vector<unsigned int> vCards1(vCards0);   //初始化另一个vector
unsigned int idx=0;
srand(time(NULL));

i=0;
unsigned int tt=total;
while(i < total)  //依次抽取52张牌
{
idx = rand() % tt;  //从vCards0中随机抽取一张牌
–tt;
vCards1[i++]=vCards0[idx];  //放入vCards1

//从vCards0中删除被抽取的那张牌

vector<unsigned int>::iterator vi=vCards0.begin();
unsigned int j=0;
while(j < idx)
{
++j;
++vi;
}
vCards0.erase(vi);
}

vector<unsigned int>::iterator vib=vCards1.begin();
vector<unsigned int>::iterator vie=vCards1.end();
while(vib != vie)
{
cout << *vib++ << ” “;
}
cout << endl;

return 0;
}

当然网上还有一些效率更高的算法,大家有兴趣可以找来看看。

分类: C/C++ 标签:

使用openresty+redis轻松实现网站访问统计

2017年2月16日 没有评论

网站的受访统计是网站运营和优化的一个重要参考数据,对于并发量较大的网站,我们可以通过nginx+redis的架构来简单实现页面受访统计。这主要得益于nginx的高并发性能和redis快速存取内存数据。实际应用中,我们可以使用openresty来快速搭建统计系统。

openresty集合了lua和lua-redis访问库,可以通过编写nginx.conf配置文件实现对redis数据库的存取。简单且高效。

  1. 安装和配置openresty及redis
  2. 修改nginx.conf,示例:

    http {
    include mime.types;
    default_type application/octet-stream;
    sendfile on;
    keepalive_timeout 65;

    server {
    listen 8088;
    server_name www.test.com;

    location /get_pv {
    set $id_param $args;
    content_by_lua ‘
    local redis_mod = require “resty.redis”
    local redis_db= redis_mod:new()
    redis_db:set_timeout(1000) — 1 second

    local ok, err = redis_db:connect(“127.0.0.1″, 6379)
    if not ok then
    ngx.log(ngx.ERR, “failed to connect to redis: “, err)
    return ngx.exit(500)
    end

    local id = string.sub(ngx.var.id_param, 4)
    local pv, err = redis_db:get(id)
    if not pv then
    redis_db:close()
    ngx.log(ngx.ERR, “failed to get redis key: “, id, err)
    return ngx.exit(500)
    end

    if pv == ngx.null then
    redis_db:close()
    ngx.log(ngx.ERR, “no pv found for “, id)
    return ngx.exit(400)
    end

    redis_db:close()

    ngx.header.content_type = “text/plain”;
    ngx.say(pv)
    ‘;
    }
    }

    server {
    listen 9099;
    server_name www.test.com;

    location /set_pv {
    set $id_param $args;
    content_by_lua ‘
    local redis_mod = require “resty.redis”
    local redis_db= redis_mod:new()
    redis_db:set_timeout(1000) — 1 second

    local ok, err = redis_db:connect(“127.0.0.1″, 6379)
    if not ok then
    ngx.log(ngx.ERR, “failed to connect to redis: “, err)
    return ngx.exit(500)
    end

    local id = string.sub(ngx.var.id_param, 4)
    local pv = redis_db:incr(id)
    if not pv then
    redis_db:close()
    ngx.log(ngx.ERR, “failed to incr redis key: “, id, err)
    return ngx.exit(500)
    end

    redis_db:close()

    ngx.header.content_type = “text/plain”;
    ngx.say(pv)
    ‘;
    }
    }
    }

  3. 在网站页面中部署统计代码

<iframe frameborder=”0″ scrolling=”no” width=”0″  height=”0″ style=”display:none;” src=”http://www.test.com:9099/set_pv?id=page_411“></iframe>

分类: Lua, Redis, 开发 标签: , , ,

openresty在又拍云的使用

2016年12月12日 没有评论
分类: 开发 标签: , ,

Chrome浏览器手机和平板UA的判断方法

2016年12月5日 没有评论

网站页面在进行移动适配时需要考虑如何判断终端类别,除了判别IOS和安卓外,为了达到更好的用户视觉体验,还需要区分手机和平板的差别。

通常是通过UA来区分的。

Chrome上手机和平板的区别是,手机端浏览器UA比平板端多了一个“Mobile”标识:

Phone UA:
Mozilla/5.0 (Linux; <Android Version>; <Build Tag etc.>) AppleWebKit/<WebKit Rev> (KHTML, like Gecko) Chrome/<Chrome Rev> Mobile Safari/<WebKit Rev>
Tablet UA:
Mozilla/5.0 (Linux; <Android Version>; <Build Tag etc.>) AppleWebKit/<WebKit Rev>(KHTML, like Gecko) Chrome/<Chrome Rev> Safari/<WebKit Rev>

比如,以下是Galaxy Nexus上Chrome的UA示例:

Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19

可以用以下正则表达式来判别:

Phone pattern: ‘Android’ + ‘Chrome/[.0-9]* Mobile’
Tablet pattern: ‘Android’ + ‘Chrome/[.0-9]* (?!Mobile)’

更详细的说明请参考:

Chrome-User-Agent-Strings

Browser detection using the user agent

另外,下边这个页面可以显示当前浏览器的UA:

http://my-user-agent.com/

分类: js 标签: ,