月度存档: 三月 2011

Android下的vpn管理软件(一)

前几天晚上趴床上玩手机,每次上vpn的时候都要输入密码,觉得太麻烦了。懒惰使人进步嘛!上网找了一个多小时,想找一个管理vpn的,发现居然都没有,就找到一个one vpn,收费3刀,rmb的话是15元,当时还觉得奇怪,这么简单的功能,为什么都没有呢,于是想自己写一个。后来发现这种情况不是没有理由的!已经过去三天了,还是可耻地没写好,惭愧啊!不过思路很明确了,继续看看dev guide和examples熟悉下。

网上都能搜到的就不写了,主要记录下折腾过程。先不用说的,配环境,官网在这,照例问候一下万恶的gfw。下载SDK, ADT plugin for eclipse。添加AVD,跑起hello,world,一切到这里都很顺利。之后先扫了扫develop guide,内容不少,估计完全看完太慢了,我就是想弄个简单的功能,应该不用这么复杂。于是看api里,发现居然没有vpn相关的内容,这下觉得不太对了。官方maillist里搜了搜,发现居然没有公布出来vpn相关的api,要做这方面的内容的话得用几个private package。一通搜索后,找到了隐藏的package,这里

有了javadoc,准备先按这个试试,import了一下,显示not resolved,居然没有在android2.2.jar里面吗,坑爹吗这不是。于是上网找源码,又纠结了会,我只要android sdk的源码哇,找出来好几个都是android的,总共2.6G。。。最后这里找到源码。这里把源码attach到android2.2.jar。源码里果然是有的。但看了看源码后发现不知道它是怎么连接的vpn,连password都没有出现过,连接的函数都是未被实现的,又囧到了。

想想换一条路吧,好像apk文件是可以反编译的,手机里root explorer搜一通后,定位到vpnservices.apk和vpnservice.odex,传到电脑上,附带的还是/system/framework下的那些odex文件。这里把odex转成dex,实际操作时有点出入,先是生成out文件夹时出现java runtime error : bad magic value,搜索未果,在这里 下载1.2.6版的baksmali后解决,然后就是生成out目录时很要几个odex文件,就是之前拷的那几个,具体的看提示吧。然后把dex转成java代码,方法在这里。转出了源代码一看有些不太对劲啊,效果一般般,不过把package名到google code search上一搜,直接就出来了,真是囧。

最后得到两份可能工作的源码,都是在google code search上搜的。package名分别是com.android.settings.vpn和com.android.server.vpn,但每一份都需要自己把sdk源代码中的android.net.vpn放到工程中去,再根据一些错误提示放点另外的类,具体的试一下就知道。然后还有一个很重要的东东,IVpnService.aidl,这东西也是搜出来的,随之一起还有vpnprofile 的一个profile,也放到工程里,eclipse会自动生成两个类。再就是修改一些xml之类,让两个工程没错误。

我个人是倾向于用com.android.server.vpn那个package里的东西来做的,它是定义了一个bindservice,不提供任何界面,需要用户自己去写。com.android.settings.vpn那个就是手机里的那个vpn设置,我非常怀疑one vpn就是在上面改了点代码然后发布出来的,因为界面都一模一样,就是加了个保存密码的勾。不过估计这个设置应该也是和 android一样的apache授权,随便用。先这样吧,再看看develop guide,最近好忙,实在没时间就直接拿第二个来改好了。。。

update:
整理后vpn server的代码
整理后vpn settings的代码

虾米自动签到

罪过罪过。。好久不写。最近用了虾米,歌是挺多,就是觉得网站好乱,下歌也还要积分。我又从来不能坚持登陆的,于是用cron + python写个定时登录脚本。很简单,直接上代码。

#!/usr/bin/python
# encoding:utf-8

import cookielib, urllib2, urllib, StringIO, gzip, os, time
import sys

if len(sys.argv) != 3:
    exit(0)

def get_raw_content(rev):
    if rev.headers.has_key('Content-Encoding'):
        fileobj = StringIO.StringIO()
        fileobj.write(rev.read())
        fileobj.seek(0)
        gzip_file = gzip.GzipFile(fileobj=fileobj)
        content = gzip_file.read()
        fileobj.close()
    else:
        content = rev.read()

    return content

LOG = True
LOG_FILE = os.environ['HOME'] + '/.xiami_signin_log'

SIGNIN_HEADERS = {
    'Accept' : '*/*',
    'Accept-Charset' : 'UTF-8,*;q=0.5',
    'Accept-Encoding' : 'gzip,deflate,sdch',
    'Accept-Language' : 'en-US,en;q=0.8',
    'Connection' : 'keep-alive',
    'Content-Length' : 0,
    'Content-Type' : 'application/x-www-form-urlencoded',
    'Host' : 'www.xiami.com',
    'Origin' : 'http://www.xiami.com',
    'Referer' : 'http://www.xiami.com/',
    'User-Agent' : 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Ubuntu/10.04 Chromium/11.0.672.2 Chrome/11.0.672.2 Safari/534.20',
    'X-Requested-With' : 'XMLHttpRequest'
}

LOGIN_HEADERS = {
    'Accept' : 'application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5',
    'Accept-Charset' : 'UTF-8,*;q=0.5',
    'Accept-Encoding' : 'gzip,deflate,sdch',
    'Accept-Language' : 'en-US,en;q=0.8',
    'Cache-Control' : 'max-age=0',
    'Connection' : 'keep-alive',
    'Content-Type' : 'application/x-www-form-urlencoded',
    'Host' : 'www.xiami.com',
    'Origin' : 'http://www.xiami.com',
    'Referer' : 'http://www.xiami.com/member/logout',
    'User-Agent' : 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Ubuntu/10.04 Chromium/11.0.672.2 Chrome/11.0.672.2 Safari/534.20',
}

LOGIN_DATA = {
    'done' : 'http://www.xiami.com/',
    'type' : '',
    'email' : sys.argv[1],
    'password' : sys.argv[2],
    'submit' : '登 录'
}
signin_url = 'http://www.xiami.com/task/signin'
login_url = 'http://www.xiami.com/member/login'

TIMEOUT = 100

def do_sign(data):
    success = True
    try:
        opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.CookieJar()))
        urllib2.install_opener(opener)
        request1 = urllib2.Request(login_url, data = urllib.urlencode(data), headers = LOGIN_HEADERS)
        rev1 = urllib2.urlopen(request1)

        request2 = urllib2.Request(signin_url, headers = SIGNIN_HEADERS, data = {})
        rev2 = urllib2.urlopen(request2)
        res = get_raw_content(rev2)
    except:
        success = False

    if success and len(res) > 100:
        success = False

    if LOG:
        log_file = open(LOG_FILE, 'a')
        log_file.write('%s %s signin %s\n' % (time.strftime('%Y-%m-%d %H:%M:%S'), data['email'], str(success)))
        log_file.close()

    if not success:
        time.sleep(TIMEOUT)
        do_sign(data)

do_sign(LOGIN_DATA)

存好后再 crontab -e,输入
0 12 */1 * * python /path-to-xiami_signin.py email password