merlin custom ddns with aliyun

首先要感谢opkg这个工具,让我们可以方便的在路由器上使用python和pip。

1
2
$ opkg install python-pip
$ pip install aliyun-python-sdk-alidns

安装好后先写一个脚本找到自己域名的RecordID。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/opt/bin/python
from aliyunsdkcore import client
from aliyunsdkalidns.request.v20150109 import DescribeDomainRecordsRequest
from aliyunsdkalidns.request.v20150109 import UpdateDomainRecordRequest
import sys
if __name__ =='__main__':
clt = client.AcsClient('Key........','Secret..................',
'cn-hangzhou')
rquest=DescribeDomainRecordsRequest.DescribeDomainRecordsRequest()
request.set_accept_format('json')
request.set_DomainName('fire3.xyz')
result = clt.do_action(request)
print result

然后写一个小脚本,放在 /jffs/scripts/home.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/opt/bin/python
from aliyunsdkcore import client
from aliyunsdkalidns.request.v20150109 import DescribeDomainRecordsRequest
from aliyunsdkalidns.request.v20150109 import UpdateDomainRecordRequest
import sys
if __name__ =='__main__':
clt = client.AcsClient('Key........','Secret..................',
'cn-hangzhou')
request=UpdateDomainRecordRequest.UpdateDomainRecordRequest()
request.set_RecordId(83035279)
request.set_Value(sys.argv[1])
request.set_RR('home')
request.set_Type('A')
request.set_TTL('600')
result = clt.do_action(request)

再写一个小脚本/jffs/scripts/ddns-start调用上面的python:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
IP=`ip addr show ppp0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1`
if [ X"$IP" == X"" ]
then
/sbin/ddns_custom_updated 0
exit -1
fi
/jffs/scripts/home.py $IP
/sbin/ddns_custom_updated 1

大功告成。注意 /jffs/scripts/ddns-start是默认的ddns设置脚本,名字不可以变动。见这里

hexo no deployer git

奇怪,另外一台新配置的hexo环境上clone出来的blog,deploy时报没有相应的deployer git。解决方法如下::

npm install hexo-deployer-git --save

IP地址冲突,静态IP变169

办公环境里面的一台虚拟机,有阵子没有重启过了,重启了一次,发现IP失灵了。
明明是个静态IP,非要给我设置成169的微软私有IP,反复禁用网卡,再启用网卡,偶尔还会报IP冲突的错误。
经过一番折腾,最终还是在google找到了 答案

解决方法如下,打开注册表进入到这个目录下::

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

新建一个DWORD 32位值: ArpRetryCount,值为0.

重启即可。原因还是交换机那边设置的问题。

centos7 setup shadowsocks-libev

安装Shadowssocks服务端

1
2
3
wget https://copr.fedorainfracloud.org/coprs/librehat/shadowsocks/repo/epel-7/librehat-shadowsocks-epel-7.repo
mv librehat-shadowsocks-epel-7.repo /etc/yum.repos.d/
yum install shadowsocks-libev

接下来修改配置文件: /etc/shadowsocks-libev/config.json

类似如下配置:

1
2
3
4
5
6
7
8
{
"server":"0.0.0.0",
"server_port":9000,
"local_port":1080,
"password":"password",
"timeout":60,
"method":"aes-256-cfb",
}

配置防火墙:

1
2
3
firewall-cmd --permanent --add-port=9000/tcp
firewall-cmd --permanent --add-port=9000/udp
firewall-cmd --reload

启动shadowsocks-libev

1
service shadowsocks-libev start

开机启动

1
systemctl enable shadowsocks-libev.service

安装kcptun服务端

1
2
3
cd /root
wget https://github.com/xtaci/kcptun/releases/download/v20161009/kcptun-linux-amd64-20161009.tar.gz
tar xvf kcptun-linux-amd64-20161009.tar.gz

Install supervisord:

1
2
3
yum -y install python-pip
pip install supervisor
echo_supervisord_conf > /etc/supervisord.conf

Add tcptun service to supervisord:

1
2
3
4
5
6
7
8
9
cat <<EOF >> /etc/supervisord.conf
[program:tcptun]
command = /root/server_linux_amd64 -l :9002 -t 127.0.0.1:9000 --crypt none --mtu 1200 --nocomp --mode normal --dscp 46
user = root
autostart = true
autoresart = true
stderr_logfile = /var/log/supervisor/tcptun.stderr.log
stdout_logfile = /var/log/supervisor/tcptun.stdout.log
EOF

为kcp服务端配置防火墙:

1
2
3
firewall-cmd --permanent --add-port=9002/tcp
firewall-cmd --permanent --add-port=9002/udp
firewall-cmd --reload

启动supervisord:

1
2
mkdir -p /var/log/supervisor/
supervisord -c /etc/supervisord.conf

开机启动supervisord:

1
echo "supervisord -c /etc/supervisord.conf" >> /etc/rc.local

优化服务器内核配置

修改配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cat <<EOF >> /etc/sysctl.conf
#TCP OPT
fs.file-max = 51200
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.core.netdev_max_backlog = 250000
net.core.somaxconn = 4096
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_mem = 25600 51200 102400
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_congestion_control = hybla
#TCP OPT END
EOF

设置生效:

1
sysctl -p

pip local mirror

pip安装软件方便,但是在一个没有互联网的环境里就抓瞎了。发现了一个这个好工具:

https://github.com/wolever/pip2pi 可以方便的把pip软件依赖的各种py包都爬下来,利用 pip2tgz 命令就可以了:

1
$ pip2tgz packages/ mkdocs

Hack bilibili for fun --- Episode 2

链接URL一目了然后,需要弄清除URL的含义细节,许多字段都可以顾名思义,比如如下例子:

1
http://api.bilibili.com/list?_device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&order=hot&page=1&pagesize=8&platform=android&tid=82&type=json&sign=9ba57bd5befcf86d9ec5917af0b7e368

可以看到 _hwid 类似机器代码,可能时IMEI识别码之类的。appkey这是这个应用统一的一个key,所有的这个安卓应用都是用这个key。order为排序方法,page和pagesize是页面编号和大小。platform所有链接均为android。tid不同,为B站的频道识别码。type均为json,最最关键的时sign这个字段,这个字段是这个URL的一个签名字段,api服务器需要检查这个字段才认可这个请求。我们需要搞清除sign的生成算法。在这里,不得不再感谢未混淆的代码以及一些开源软件事先的工作,比如 you-get。我们先打开源程序中程序员的调试插桩,看看原来程序员的调试打印:

修改这个文件: tv/danmaku/android/util/DebugLog.smali , 把这个里面的constructor里面的 const/4 v0, 0x0 全部改为 const/4 v0, 0x1 。就可以看到原来程序员的打印了。

综合BlaUriBuilder这个文件,看getSignedQuery实现,不难发现是用MD5算了一串字符串生成了sign。那么算的究竟时什么东西呢?原来程序员调试时也加了打印:

1
2
3
I/BLAUriBuilder(26691): signed query _device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&order=hot&page=1&pagesize=8&platform=android&tid=145&type=json
I/BLAUriBuilder(26691): escaped query _device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&order=hot&page=1&pagesize=8&platform=android&tid=145&type=json&sign=3f5a589a226ffacea56e4ac96b7d3583
I/BLAUriBuilder(26691): escaped url http://api.bilibili.com/list?_device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&order=hot&page=1&pagesize=8&platform=android&tid=145&type=json&sign=3f5a589a226ffacea56e4ac96b7d3583

可以看到,第一行中内容就是MD5计算的输入,但这个输入并不完整,仔细看还缺少了一个LibBili.getAppSecret获取的AppSecret,同样通过代码插桩,我们很方便的获取到这个Appsecret为ea85624dfcf12d7cc7b2b3a94fac1f2c,接下来就可以验证算法了,使用python:

1
2
3
4
>>> hashlib.md5(bytes('_device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&order=hot&page=1&pagesize=8&platform=android&tid=145&type=json')).hexdigest()
'81eae43caf2fc31516cd2640be9fa747'
>>> hashlib.md5(bytes('_device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&order=hot&page=1&pagesize=8&platform=android&tid=145&type=jsonea85624dfcf12d7cc7b2b3a94fac1f2c')).hexdigest()
'3f5a589a226ffacea56e4ac96b7d3583'

可以看到跟上面打印中的sign计算出来一致。至此,sign的生成方法一目了然。 普通的获取获取一个频道的视频均是这个URL,另外就是搜索的URL生成:

1
2
3
I/BLAUriBuilder(26691): signed query _device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&keyword=%E4%B9%8C%E9%BE%9F&order=default&page=1&pagesize=20&platform=android&type=json
I/BLAUriBuilder(26691): escaped query _device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&keyword=%E4%B9%8C%E9%BE%9F&order=default&page=1&pagesize=20&platform=android&type=json&sign=9d0886eb3d0731158c59e731b565aa25
I/BLAUriBuilder(26691): escaped url http://api.bilibili.com/search?_device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&keyword=%E4%B9%8C%E9%BE%9F&order=default&page=1&pagesize=20&platform=android&type=json&sign=9d0886eb3d0731158c59e731b565aa25

Hack bilibili for fun --- Episode 1

B站的视频虽说本人甚少参观,但是本着研究以及造福大众的学术态度,还是光顾并折腾了一番。

先想办法窥测一下B站的API吧。老方法,通过反编译B站的安卓客户端进行,这是最原汁原味的API。

B站的客户端 : http://app.bilibili.com/images/android.html

这里选取怀旧版进行hack,主要原因是上面一个版本apktool居然无法解包。下面一个“怀旧版”也遇到了一些小的技术问题,
按照默认方式解包时无法正常打包,资源文件故障。资源文件故障的解决方法是不解包资源文件。用下面命令来解包, -r 表示保留资源文件不解压,可以有效解决打包时
资源文件报错的问题。

1
apktool d -r ./BiliPlayer_White.apk

用这个小脚本调试:

1
2
3
4
5
6
7
rm -rf build signed
mkdir build
mkdir signed
adb shell pm uninstall tv.danmaku.bilixl
apktool build BiliPlayer_White -o build/Biliplayer.apk
d2j-apk-sign.sh -f build/Biliplayer.apk -o signed/Biliplayer.apk
adb install signed/Biliplayer.apk

先想办法找到B站的Http请求URL。

我先从反编译的一堆smali里面逛了逛,另外配合d2j-dex2jar工具转换的jar包和jd-gui工具看了看,评估一下这个工作量。不看不知道,一看吓一跳,
B站的程序员实在是良心大大的好程序员,思路清晰,函数封装合理,最最最重要是,代码没有加入混淆。都知道,安卓代码不加混淆反编译就是明文啊,这
可阅读性提高太多了。你看,人家目录名都放的多么符合程序员的编程规范: smali/tv/danmaku/bili/api , 这还用说么,这不是api这是啥。先不忙着激动,
让我们来找找HttpGet这个关键字。一搜一大把啊,太符合逻辑了。顺便说一句,HttpGet这个是apache http接口里面的,就算混淆了代码,用了这个也还是能追踪到。
继续筛选我们要的东西,buildHttpGet被发现,太有爱了,要我我也喜欢这个命名。我得写了统一的接口来生成http请求啊,我得封装一组操作来执行Get操作啊,于是乎就
有了buildHttpGet,接下来就简单了,开始加Log:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
.method public buildHttpGet()Lorg/apache/http/client/methods/HttpGet;
#.locals 2
# add a local register by fire3
.locals 3
.prologue
.line 105
new-instance v0, Lorg/apache/http/client/methods/HttpGet;
invoke-virtual {p0}, Ltv/danmaku/bili/api2/utility/BLAUriBuilder;->build()Landroid/net/Uri;
move-result-object v1
invoke-virtual {v1}, Landroid/net/Uri;->toString()Ljava/lang/String;
move-result-object v1
#============= add by fire3 start ============
const-string v2, "fire3-bili-Get"
invoke-static {v2, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
#============= add by fire3 end =============
invoke-direct {v0, v1}, Lorg/apache/http/client/methods/HttpGet;-><init>(Ljava/lang/String;)V
.line 106
.local v0, "httpRequest":Lorg/apache/http/client/methods/HttpGet;
invoke-direct {p0, v0}, Ltv/danmaku/bili/api2/utility/BLAUriBuilder;->setupRequest(Lorg/apache/http/HttpRequest;)V
.line 108
return-object v0
.end method

找到合适的地方加个Log太Easy了,看上面代码就知道。然后pack程序,装上执行,点击点击看看,就可以在adb shell里面用logcat搜了:

1
2
3
4
5
6
30|root@generic:/ # logcat | grep fire3
I/fire3-bili-Get( 1714): http://api.bilibili.com/bangumi?_device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&btype=2&platform=android&type=json&sign=1d1ddc1de2d3741a5d20206034852284
I/fire3-bili-Get( 1714): http://api.bilibili.com/index?_device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&platform=android&type=json&v=2&sign=ebe01fa7223eb329c177792f5ace70da
I/fire3-bili-Get( 1714): http://api.bilibili.com/list?_device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&order=hot&page=1&pagesize=8&platform=android&tid=145&type=json&sign=3f5a589a226ffacea56e4ac96b7d3583
I/fire3-bili-Get( 1714): http://api.bilibili.com/list?_device=android&_hwid=ccbb856c97ccb8d2&appkey=c1b107428d337928&order=hot&page=1&pagesize=8&platform=android&tid=145&type=json&sign=3f5a589a226ffacea56e4ac96b7d3583

这个是货真价实的一手资料!下一步就开始分析接口了。B站的工作正式启动,未完待续。

mate 7 logcat

用手机进行调试,在电脑上不显示logcat信息。

解决方法:

在拨打电话界面,录入*#*#2846579#*#*
自动进入开发界面菜单,按以下步骤:

ProjectMenu -> Background setting -> Log Setting 选择打开即可.