• 让nginx列目录及对目录进行密码保护

    1、如何让nginx列目录

    在对应的网站配置段中,加入:

    location /_files

    {

        root /home/blog.creke.net;

        autoindex on;

        autoindex_exact_size off;

        autoindex_localtime on;

    }

    解释一下:

    root是指当前的网站根文件夹,例子中列出的根目录其实是/home/blog.creke.net/_files目录,如果不填则沿用上层的root配置;

    autoindex是是否对该location匹配的目录在找不到索引文件(index.html、index.php等)时,列出目录,默认为off;

    autoindex_exact_size是是否输出准确的大小,如果on则输出byte单位的大小,off则用GB、MB、KB来近似表示,默认为on;

    autoindex_localtime是否以服务器时间输出文件时间,off则用GMT时间输出,默认为off。

    参考:http://wiki.nginx.org/HttpAutoindexModule

    2、对目录进行密码保护:

    在对应目录的location中加入:

    auth_basic "Creke Server Auth";

    auth_basic_user_file /usr/local/nginx/conf/htpasswd;

    其中auth_basic是验证时显示的标题,auth_basic_user_file是对应的用户名密码,一行一个,与apache的“.htpasswd”一样。

    参考:http://wiki.nginx.org/HttpAuthBasicModule

    最后,给出一个使用perl生成htpasswd中认证用户名密码的脚本,方便生成:

    #!/bin/bash
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
    export PATH
    
    echo "====================================="
    echo "# A tool like htpasswd for Nginx    #"
    echo "#-----------------------------------#"
    echo "# MOD BY Creke                      #"
    echo "====================================="
    
    #set UserName
    
    	username=""
    	read -p "Please input UserName:" username
    	if [ "$username" = "" ]; then
    		echo "Error:UserName can't be NULL!"
    		exit 1
    	fi
    	echo "==========================="
    	echo "UserName was: $username"
    	echo "==========================="
    
    #set password
    
    	unpassword=""
    	read -p "Please input the Password:" unpassword
    	if [ "$unpassword" = "" ]; then
    		echo "Error:Password can't be NULL!"
    		exit 1
    	fi
    	echo "==========================="
    	echo "Password was: $unpassword"
    	echo "==========================="
    password=$(perl -e 'print crypt($ARGV[0], "pwdsalt")' $unpassword)
    
    echo "$username:$password"

    2012.10.28 / 暂无评论 / 1,917 次点击 / 分类: 所谓技术

  • CentOS安装Ruby

    安装依赖

    yum install zlib-devel curl-devel openssl-devel apr-devel apr-util-devel expat-devel gettext-devel readline-devel gdbm-devel tcl-devel tk-devel

    手动安装libyaml否则会提示“yaml.h is missing. Please install libyaml. Failed to configure psych. It will not be installed.”

    wget http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz

    tar zxf yaml-0.1.4.tar.gz

    cd yaml-0.1.4

    ./configure --prefix=你的目录

    make

    make install

    手动安装libffi否则会提示“ffi.h is missing”

    wget ftp://sourceware.org/pub/libffi/libffi-3.0.11.tar.gz

    tar zxf libffi-3.0.11.tar.gz

    cd libffi-3.0.11

    ./configure --prefix=你的目录

    make

    make install

    ln 安装目录/lib/libffi-3.0.11/include/ffi.h /usr/local/include/ffi.h

    安装ruby 1.8(1.9的digest有问题,不知道何故)

    wget http://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7.tar.gz

    tar zxf ruby-1.8.7.tar.gz

    cd ruby-1.8.7

    ./configure --prefix=你的目录 --enable-shared --enable-pthread

    make

    make install

    1.9内含rubygem,但1.8要手动安装:

    wget http://production.cf.rubygems.org/rubygems/rubygems-1.8.24.tgz

    tar zxf rubygems-1.8.24.tgz

    cd rubygems-1.8.24

    ruby setup.rb

    就是这样。搞定。

    2012.09.10 / 1 条评论 / 3,391 次点击 / 分类: 所谓技术

  • Galaxy Nexus无需安装CWM recovery手动升级OTA包到Android4.1

    Galaxy Nexus已经开始推送Android 4.1.1了。但是在一个国家和地区经常被各大应用鄙视的地方,OTA包的下载也很容易失败。所以,在大家看到一个开膛的安卓机器人冒出感叹号时,有必要手动升级OTA包啦。

    假设已经安装了4.0.4的yakju原版。如果没有,请参考各大刷机教程自行解决。

    首先,手动下载Android 4.0.4升级到Android 4.1.1的OTA更新,点击这里下载这个帖子还会有各种OTA包的历史更新记录

    然后,在这里下载CWM recovery,我们不需要把它刷到手机哦。确认你的手机的bootloader已经unblock,即解锁。方法是开机画面Google下面的锁是否打开。

    接着,确认驱动安装完毕,确认r3-galaxynexus-superboot工具已经准备好。

    好了,可以吧OTA的zip包放进sdcard中,具体文件夹不限,只需要是/sdcard下的某个目录即可。

    关机,拔掉数据线。然后同时按住音量加、减键,进入fastboot模式。

    进入galaxynexus-superboot目录,把CWM recovery的文件重命名为cwm.img放进去。

    运行命令:

    fastboot boot cwm.img

    在手机中:

    选择“install zip from sdcard”

    选择“choose zip from sdcard”

    选择刚刚放进去的ZIP包。

    步骤就这么多,慢慢等升级完毕。

    如何ROOT?

    这里下载最新版的GNex TOOLKIT。

    安装,运行。

    在GNex TOOLKIT中选择对应的手机版本。

    然后打开手机调试模式,在GNex TOOLKIT中选择ROOT,等待。

    就这么简单。

    如何加快OTA?

    在设置时间里,去掉确定时间和时区的两个勾。

    在应用里,清除Google服务和Google合作伙伴的数据。

    输入*#*#2432546#*#*,即*#*#checkin#*#*的意思。

    最后点击更新系统,就可以看到OTA更新了。

    2012.07.14 / 1 条评论 / 3,762 次点击 / 分类: 所谓技术

  • Apache结合mod_dav_svn和mod_authz_svn打造SVN服务器

    制作SVN服务器的软件和工具有很多,比如每个SVN都有的svnserve,以及图形化界面超容易使用的VisualSVN Server。但是,现在既然有Apache服务器,那就直接用就是了,而且还可以使用Web浏览目录。

    首先,前往这里下载对应的SVN发行包,我下载的是Win32Svn。里面自带mod_dav_svn.so与mod_authz_svn.so。使用与Apache2.2,其他版本请自行测试。

    然后,把Win32Svn解压缩,如d:\Subversion,然后在系统环境变量中加上d:\Subversion。

    接着,把mod_dav_svn.so与mod_authz_svn.so拷贝到apache的modules目录。

    修改httpd.conf,把以下两行前面的“#”注释去掉:

    LoadModule dav_fs_module modules/mod_dav_fs.so
    LoadModule dav_module modules/mod_dav.so

    在所有LoadModule的最后加上下面两行:

    LoadModule dav_svn_module modules/mod_dav_svn.so
    LoadModule authz_svn_module modules/mod_authz_svn.so

    假设使用d:\svn作为仓库的地址,则在httpd.conf或对应虚拟主机的配置中加上:

    #SVN START
    <Location /svn>
        DAV svn
        SVNParentPath D:\svn
        AuthType Basic
        AuthName "blog.creke.net SVN"
        AuthUserFile D:\svn\.htpasswd
        AuthzSVNAccessFile D:\svn\.ht_svn_authz
        Require valid-user
    </Location>
    #SVN END

    具体的配置参数可以查看这里这里

    其中的.htpasswd是用户密码文件,与apache的一样。

    .ht_svn_authz是访问控制文件,可以在svnadmin create后,在conf目录下authz.conf找到该文件带有注释的原型。

    如果在blog.creke.net的虚拟主机中加上以上配置,再执行“svnadmin create d:\svn\rep1”后,我们访问http://blog.creke.net/svn/rep1时,就会访问到对应的rep1的仓库。

    使用这个方法,apache就会兼做svn服务器,就不需要单独启动svnserve了。

    2012.07.10 / 2 条评论 / 4,202 次点击 / 分类: 所谓技术

  • php5.2配置使用memcached(附php_memcache.dll官方下载)

    当前PHP都已经到5.4了,但是我还是5.2,没办法,已经从以前的更新强迫症到现在的更新拖延症了。所以说一下PHP5.2的memcached怎么配置使用。

    这里下载最新的pecl包,即使版本不一样,只需要保证是5.2的即可,如pecl-5.2.6-Win32.zip。然后把压缩包里的php_memcache.dll解压缩到PHP安装目录下的ext文件夹中。

    打开php.ini,在extension列表后加上:

    extension=php_memcache.dll

    打开memcached,使用下面脚本测试memcached和PHP联合是否成功:

    <?php
    	$mem = new Memcache;
    	$mem->connect('localhost', 11211) or die ("Could not connect");
    	
    	$mem->set('test', 'testMem');
    
    	echo $mem->get('test');
    	
    ?>

    OK,就是这样。

    2012.06.26 / 1 条评论 / 4,679 次点击 / 分类: 所谓技术

  • Android中Java编写的APK使用apktool反编译并修改smali

    今天装了某个游戏,游戏中有“商店”,可以用金币购买相关物品。而获得金币的途径,是用人民币购买(1元100只)或者安装该公司的其他应用(安装3款得一点点)。

    这显然不科学啊!

    当然,程序在我机子上,我们当然能够用科学的手段来对付不科学的游戏货币商城制度。

    1、使用apktool进行反编译,得到smali的字节码

    假设游戏安装文件为my_game.apk,我们将把它反编译到mygame目录下。

    这里下载apktool和对应的dependencies,把apktool和对应的dependencies加压缩到一起,并将该文件夹添加到path环境变量中。我在使用Windows系统,这时候apktool的解压文件夹有以下内容:

    aapt.exe

    apktool.bat

    apktool.jar

    然后对my_game.apk进行反编译,运行命令:

    apktool d my_game.apk mygame

    可以看到apktool将游戏反编译到mygame文件夹中。其中的smali就是对应的字节码。

    2、修改smali字节码

    关于smali字节码的寄存器可以参考这里,类型、函数和成员可以参考这里,操作符号可以参考这里

    当然,由于程序已经混淆,所以不能从文件名和包名中猜测相关信息。这时候有好几个办法定位到要修改的地方。如调试设断点,在这里有教程。还可以通过资源和字符串定位,这是我现在使用的方法,因为我的调试环境还没搭好……

    我注意到,某一个与购买相关的按钮图片的id编号为“0x7f020093”,于是在smali中搜索,最后在某个文件夹,也就对应Java的某个包中找到g.smali,这个文件包含了字符串“0x7f020093”。然后,点击购买时,会提示“金币不足,无法购买”,这是文本信息。也就是说,可以在g.smali中搜索该字符串,或者字符串子串来进行程序上下文的定位。当然,直接搜索中文字符串是一无所获的,因为反编译器将中文以utf8的裸编码格式表现。这时候在g.smali中搜索“\u91d1\u5e01\u4e0d\u8db3,\u65e0\u6cd5\u8d2d\u4e70”,找到详细位置!具体代码片段如下:

    sget-object v0, La/f/c;->s:La/a/b/g;

    iget-object v9, v0, La/a/b/g;->j:Ld/a/b;

    iget v10, p2, La/d/n;->f:I

    iget v0, v9, Ld/a/b;->v:I

    if-ge v0, v10, :cond_0

    invoke-static {}, Lcom/gale/manager/f;->a()Lcom/gale/manager/f;

    move-result-object v0

    const-string v1, "\u91d1\u5e01\u4e0d\u8db3,\u65e0\u6cd5\u8d2d\u4e70"

    invoke-virtual {v0, v1}, Lcom/gale/manager/f;->a(Ljava/lang/String;)V

    :goto_0
    return-void

    :cond_0
    neg-int v0, v10

    iput v0, v9, Ld/a/b;->x:I

    需要关注的是“if-ge”这句,意思是如果v0大于等于v10,则跳到cond_0执行,否则显示“金币不足,无法购买”并返回。

    我们可以直接将“if-ge”改成“if-le”解决问题,不过这时金币会在购买后变负数,说不定会把游戏crash。所以,更好的修改方法如下:

        sget-object v0, La/f/c;->s:La/a/b/g;

        iget-object v9, v0, La/a/b/g;->j:Ld/a/b;

        iget v10, p2, La/d/n;->f:I

        iget v0, v9, Ld/a/b;->v:I

        if-ge v0, v10, :cond_0
        goto/16 :cond_0

        :goto_0
        return-void

        :cond_0
        move v0, v10

        iput v0, v9, Ld/a/b;->x:I

    意思是,即使当前金币小于购买所需金币,也跳到条件成立的地方执行。另外,执行时会将玩家的金币数加上所需金币的相反数,即“neg-int v0, v10”,将其改为“move v0, v10”就可以每次都把玩家的金币数加上所需金币数。最终效果则是,即使金币不足也可以购买,并且越买钱越多。

    3、打包、签名和安装修改后的apk

    修改完了,就可以打包回apk了。执行以下命令:

    apktool b mygame

    在mygame目录下的dist在会看到打包好的apk。

    当然,现在一般是无法安装的,因为apk还没有签名。下面就来签名。签名需要keystore文件,我已经有专用的keystore了,如果还没有,请参阅这里进行生成。

    执行以下命令为重新编译的my_game.apk签名:

    jarsigner -verbose -keystore creke.keystore my_game.apk Alias_name

    最后,在安装到手机前,需要把手机中的已有版本先卸载,因为如果签名不同,是不能覆盖安装的,会提示“应用程序未安装”错误。

    4、其他

    Windows下的aapt似乎不能对非本地磁盘进行读写,比如我原来在内存盘中进行操作,apktool总是提示aapt出错,不能打包apk。后来放到本地磁盘中进行才一切正常。

    最后说一句,好的游戏从来不会用奇怪的货币和商城来吸引玩家或者玩家的钱财。

    2012.05.09 / 9 条评论 / 16,094 次点击 / 分类: 所谓技术

  • PHP与JAVA使用AES128位加密通信

    本来JAVA和JSP之间加密通信好好的,相同的函数,相同的处理,不会有其他大问题。不过有时候就是蛋疼啊,于是就有了PHP与JAVA间使用AES进行加密通信。

    PHP的AES128位由mcrypt模块提供,称为MCRYPT_RIJNDAEL_128。

    JAVA的AES默认就是128位的。

    加密模式有好几种,不同的语言不同的库支持的情况不同。这里选择的是安全且通用的CBC模式。

    至于padding,这是最头疼的问题,因为PHP的padding与Java的padding不一样。如果使用NoPadding,则默认又用不了CBC模式。所以,最好的解决方法是自己padding——在原文末尾加上若干个空格,使原文凑齐16的倍数的长度。当然,原文末尾也可能是空格结束啊,那怎么办?没办法,只有强制原文末尾加上一个换行。这样子,每次解密后,将最右边的换行以及其右边的空格裁剪掉,就得到原文了。

    另外,为了兼容,在加密和解密时,需要将内容转换成16进制的字符数组。这样一来,即使加密/解密的内容不是普通文本,而是二进制数据,也可以轻松传送啦。

    JAVA方面

    初始化代码:

            try {
                cipherEnc = Cipher.getInstance("AES/CBC/NoPadding");
            } catch (NoSuchAlgorithmException ex) {
                ex.printStackTrace();
            } catch (NoSuchPaddingException ex) {
                ex.printStackTrace();
            }
            try {
                cipherDec = Cipher.getInstance("AES/CBC/NoPadding");
            } catch (NoSuchAlgorithmException ex) {
                ex.printStackTrace();
            } catch (NoSuchPaddingException ex) {
                ex.printStackTrace();
            }
    
            key = new SecretKeySpec(keyStr.getBytes(), "AES");
            iv = new IvParameterSpec(ivStr.getBytes());

    加密解密及其核心函数:

        public static String padRight(String s, int n) {
            return String.format("%1$-" + n + "s", s);
        }
    
        public static String padLeft(String s, int n) {
            return String.format("%1$#" + n + "s", s);
        }
        
        public String encrypt(SecretKeySpec enc_key, IvParameterSpec enc_iv, String str){
            byte[] ret = null;
            
            try {
                cipherEnc.init(Cipher.ENCRYPT_MODE, enc_key, enc_iv);
                ret = cipherEnc.doFinal(padRight(str,
                        ((int)Math.ceil(str.length() / 16.0))*16).getBytes());
            } catch (Exception ex) {
                ex.printStackTrace();
                return null;
            }
            
            return byteArray2HexString(ret);
        }
        
        /*
         * str is Hex String
         */
        public String decrypt(SecretKeySpec dec_key, IvParameterSpec dec_iv, String str){
            byte[] ret = null;
            
            try {
                cipherDec.init(Cipher.DECRYPT_MODE, dec_key, dec_iv);
                ret = cipherDec.doFinal(hexString2ByteArray(str));
            } catch (Exception ex) {
                ex.printStackTrace();
                return null;
            }
            
            try {
    			return new String(ret, "UTF-8");
    		} catch (UnsupportedEncodingException e) {
    			return null;
    		}
        }
    
        static final char[] HEX_CHAR_TABLE = {
            '0', '1', '2', '3', '4', '5', '6', '7',
            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
        };
    
        public static String byteArray2HexString(byte[] b) {
            if (b == null) {
                return null;
            }
            final StringBuilder hex = new StringBuilder(2 * b.length);
            for (final byte by : b) {
                hex.append(HEX_CHAR_TABLE[(by & 0xF0) >> 4]).append(HEX_CHAR_TABLE[(by & 0x0F)]);
            }
            return hex.toString();
        }
        
        public static byte[] hexString2ByteArray(String s) {
            if (s == null) {
                return null;
            }
            byte high, low;
            int len = s.length() / 2;
            byte[] b = new byte[len];
            for(int i=0, k=0; i<len; i++, k+=2)
            {
                high = (byte) (Character.digit(s.charAt(k), 16) & 0x0F);
                low = (byte) (Character.digit(s.charAt(k+1), 16) & 0x0F);
                b[i] = (byte) ((high<<4) | low);
            }
            
            return b;
        }

    PHP方面

    加密解密部分及其核心函数

    	static function encrypt($enc_key, $enc_iv, $data){
    		$pad = str_pad($data, ceil(strlen($data)/16.0)*16, " ");
    		
    		$method = MCRYPT_RIJNDAEL_128;
    		$mode = MCRYPT_MODE_CBC;
    		$td = mcrypt_module_open($method, '', $mode, '');
    		mcrypt_generic_init ( $td , $enc_key , $enc_iv);
    		$encrypt = mcrypt_generic($td, $pad);
    		mcrypt_generic_deinit($td);
    		mcrypt_module_close($td);
    		
    		return bin2hex($encrypt);
    	}
    	
    	static function decrypt($dec_key, $dec_iv, $data){
    		$method = MCRYPT_RIJNDAEL_128;
    		$mode = MCRYPT_MODE_CBC;
    		$td = mcrypt_module_open($method, '', $mode, '');
    		mcrypt_generic_init ( $td , $dec_key , $dec_iv);
    		$decrypt = mdecrypt_generic($td, hex2bin($data));
    		mcrypt_generic_deinit($td);
    		mcrypt_module_close($td);
    	
    		return $decrypt;
    	}
    
    if(!function_exists('hex2bin'))
    {
    	/**
    	 * Converts the hex representation of data to binary
    	 *
    	 * http://www.php.net/manual/en/function.hex2bin.php
    	 *
    	 * @param   string  $str        Hexadecimal representation of data
    	 *
    	 * @return  string              Returns the binary representation of the given data
    	 */
    	function hex2bin($data)
    	{
    		return pack("H*" , $data);
    	}
    }

    就是这样啦。什么?不懂怎么用?那就看看AES的文献,看看Java和PHP的文档再说吧。

    2012.03.08 / 6 条评论 / 8,265 次点击 / 分类: 所谓技术

  • Virtualbox虚拟硬盘lvm分区压缩体积

    Virtualbox虚拟硬盘的压缩要碰到“0”才会进行压缩。所以很蛋疼。

    在虚拟机上运行

    su -

    dd if=/dev/zero of=fillfile bs=1M

    rm fillfile

    如果不常用swap,把swap分区也压缩一下

    swapon -s

    swapoff -a #卸载/dev/VolGroup00/LogVol01

    swapon -s

    mkfs.ext3 /dev/VolGroup00/LogVol01

    mount /dev/VolGroup00/LogVol01 /root/tmp

    cd /root/tmp

    dd if=/dev/zero of=fillfile bs=1M

    rm fillfile

    shutdown -hP now

    在主机上运行

    VBoxManage modifyhd /path/to/your.vdi --compact

    记得启动虚拟机,把swap挂上

    mkswap /dev/VolGroup00/LogVol01

    swapon -a

    理论上应该没问题,但是我在虚拟机内看到实际使用了2.5G,压缩后的虚拟硬盘文件大小是4G,这差值是怎么回事?不晓得。

    所以说,还是将/、/home、SWAP三者分别放在不同的虚拟硬盘上比较好管理。还有,CentOS默认使用的lvm逻辑卷现在支持的工具太少了,维护起来相当麻烦。

    参考:Via1Via2

    2012.02.23 / 2 条评论 / 2,316 次点击 / 分类: 所谓技术

  • 在Virtualbox下自定义Android-x86的分辨率

    没写安装配置笔记,反倒先写了如何自定义Android-x86的分辨率,哈。

    1、在虚拟机添加自定义分辨率

    在虚拟机关闭以后进行。

    方法一:对应的虚拟机的xml文件的“<ExtraData>”下新开一行,加上以下内容

    <ExtraDataItem name="CustomVideoMode1" value="480x800x16"/>
    <ExtraDataItem name="CustomVideoMode2" value="320x480x16"/>

    方法二:执行命令,其中“VM name”替换为你自己的虚拟机的名字

    VBoxManage setextradata "VM name" "CustomVideoMode1" "480x800x16"
    VBoxManage setextradata "VM name" "CustomVideoMode2" "320x480x16"

    2、修改grub的menu.lst

    启动虚拟机,到debug mode下,编辑文件:

    /mnt/grub/menu.lst

    如果是手机分辨率则复制MDPI的几行,平板分辨率则复制HDPI的内容。把title改为自己想要的启动项名字,如“Android-x86 480x800x16”,在“kernel”后加上:

    UVESA_MODE=480x800

    320x480的分辨率也类似进行。

    3、在debug mode下重启Android-x86

    运行命令

    /system/bin/reboot

    即可

    2012.02.19 / 2 条评论 / 7,254 次点击 / 分类: 所谓技术

  • CentOS安装git

    CentOS默认源是没有git的,所以希望通过yum install来安装的童鞋们,不要在错误的道路上越走越远……

    所以,要从源安装,对应的命令:

    yum -y install zlib-devel openssl-devel perl cpio expat-devel gettext-devel

    wget http://git-core.googlecode.com/files/git-1.7.7.5.tar.gz

    ./configure --prefix=/usr/local/git

    make

    make install

    然后对执行文件进行链接,当然,如果安装在/usr/local目录的话,就不用这步了。

    ln -s /usr/local/git/bin/git /usr/local/bin/git

    ln -s /usr/local/git/bin/gitk /usr/local/bin/gitk

    ln -s /usr/local/git/bin/git-shell /usr/local/bin/git-shell

    ln -s /usr/local/git/bin/git-upload-pack /usr/local/bin/git-upload-pack

    ln -s /usr/local/git/bin/git-cvsserver /usr/local/bin/git-cvsserver

    ln -s /usr/local/git/bin/git-receive-pack /usr/local/bin/git-receive-pack

    ln -s /usr/local/git/bin/git-upload-archive /usr/local/bin/git-upload-archive

    常见问题

    1、如果出现“git: error while loading shared libraries: libiconv.so.2: cannot open shared object file: No such file or directory”

    在确认已经安装iconv库的情况下,执行以下命令:

    echo "/usr/local/lib" > /etc/ld.so.conf.d/git.conf

    /sbin/ldconfig

    2、如果在“git clone https://***”时出现“error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed while accessing”

    在使用git前加上“GIT_SSL_NO_VERIFY=true”的环境变量,即:

    env GIT_SSL_NO_VERIFY=true git clone https://***

    2012.01.09 / 2 条评论 / 4,735 次点击 / 分类: 所谓技术