12/10/2010

交叉编译

最近朋友给一块arm板子,让我帮忙交叉编译无线网卡驱动,因为交叉编译都没有,所以从交叉编译器到编译驱动一条龙服务啊,简单记录一下。

1) 首先交叉编译器,我用crosstool-ng交叉编译工具,还比较顺利,事先查清楚板子上arm指令集,gcc 和
glibc的版本号就可以了,arm指令集可以到这里对照着查:http://en.wikipedia.org/wiki/ARM_architecture

2) 然后编译内核,make ARCH=arm menuconfig,作一下简单配置,记得选上 wireless,接下来编译内核:make
ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- (记得export PATH
并指定刚刚编出来的交叉编译起)

如果编译过程中出现如下错误:

arm-9tdmi-linux-gnu-ld: no machine record defined

可能是 binutils 版本导致的,可以暂时注释 文件中下面两行:

ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")


3) 最后准备编译无线网卡驱动,由于我机器上的内核是2.6.36,而板子上的是2.6.29.4,所以采用如下方法编译:

make KLIB=/usr/src/linux-2.6.29.4 KLIB_BUILD=/usr/src/linux-2.6.29.4

9/01/2010

Linux 平台下函数调用的堆栈分析

先给一个很简单的函数调用的程序,如下:

#include <stdio.h>

int func(int a)
{
int i = a;
return i;
}

int main()
{
int i = 2;
func(i);
i = 1;
printf("i=%d\n", i);
return 0;
}

这个程序运行的结果是打印"i=1",我们要做的实验就是通过改变堆栈 ebp 的值,使得调用函数func 后返回到main 函数中跳过"i =
1;",从而该程序运行结果变为"i=2"。

先看看main 和 func两个函数的汇编代码:

(gdb) disassemble main
Dump of assembler code for function main:
0x080483c1 <main+0>: lea 0x4(%esp),%ecx
0x080483c5 <main+4>: and $0xfffffff0,%esp
0x080483c8 <main+7>: pushl -0x4(%ecx)
0x080483cb <main+10>: push %ebp
0x080483cc <main+11>: mov %esp,%ebp
0x080483ce <main+13>: push %ecx
0x080483cf <main+14>: sub $0x24,%esp
0x080483d2 <main+17>: movl $0x2,-0x8(%ebp)
0x080483d9 <main+24>: mov -0x8(%ebp),%eax
0x080483dc <main+27>: mov %eax,(%esp) /* argument */
0x080483df <main+30>: call 0x80483b0 <f>
0x080483e4 <main+35>: movl $0x1,-0x8(%ebp) /* return address */
0x080483eb <main+42>: mov -0x8(%ebp),%eax
0x080483ee <main+45>: mov %eax,0x4(%esp)
0x080483f2 <main+49>: movl $0x80484d0,(%esp)
0x080483f9 <main+56>: call 0x8048300 <printf@plt>
0x080483fe <main+61>: mov $0x0,%eax
0x08048403 <main+66>: add $0x24,%esp
0x08048406 <main+69>: pop %ecx
0x08048407 <main+70>: pop %ebp
0x08048408 <main+71>: lea -0x4(%ecx),%esp
0x0804840b <main+74>: ret
End of assembler dump.

(gdb) disassemble func
Dump of assembler code for function func:
0x080483b0 <func+0>: push %ebp
0x080483b1 <func+1>: mov %esp,%ebp
0x080483b3 <func+3>: sub $0x10,%esp
0x080483b6 <func+6>: mov 0x8(%ebp),%eax
0x080483b9 <func+9>: mov %eax,-0x4(%ebp)
0x080483bc <func+12>: mov -0x4(%ebp),%eax
0x080483bf <func+15>: leave
0x080483c0 <func+16>: ret
End of assembler dump.

当调用func函数时,该程序进程的堆栈发生了哪些变化呢?
首先需要传给func 的参数依次入栈,然后是函数的返回地址入栈,也就是call指令的下一条地址,进入func函数后,先把当前的 ebp
入栈,也就是上一次的栈帧地址入栈,其次分配栈空间,为函数的局部变量腾出地方。此时堆栈情况大致如下:
_________________
| int i = 2 |
| ---------------------|
| argument |
| ---------------------|
| return address |
| ---------------------|
| previous frame |
| pointer address |
| ---------------------|
| int i = a |
|________________|

我们只要把这里的 return address 改为0x080483eb即可,也就是跳过0x080483e4处的赋值语句,这样就变量 i
的值就没有改变,因此可达到实验要求的效果。怎么改呢?很明显,可以通过func函数的局部变量 i,取它的地址,就可以访问堆栈了,可以在gdb
中做这样的测试:

p /x *(&i) -----> 局部变量 i 的值
p /x *(&i+1) -----> 之前的栈帧地址
p /x *(&i+2) -----> 函数返回地址
p /x *(&i+3) -----> 函数参数


以下完整代码如下:

#include <stdio.h>

int func(int a)
{
int i = a;
*(&i+2) = *(&i+2)+7; /* 0x080483eb -0x080483e4 = 0x7 */
return i;
}

int main()
{
int i = 2;
func(i);
i = 1;
printf("i=%d\n", i);
return 0;
}


注:以上代码均在x86, Linux 2.6.34, gcc 4.2.3的环境中调试运行。

8/20/2010

常见协议的报文格式

/*
* TCP/IP 协议类型
*/
#define IPPROTO_IP 0 // IP
#define IPPROTO_ICMP 1 // ICMP
#define IPPROTO_TCP 6 // TCP
#define IPPROTO_UDP 17 // UDP

/*
* 其它定义
*/
#define ETH_ALEN 6 // 以太网地址大小
#define ETH_HLEN 14 // 以太网头部大小
#define ETH_DATA_LEN 1500 // 最大帧负载数据大小
#define ETH_FRAME_LEN 1514 // 最大帧大小,头部+负载数据

/*
* 常见协议定义
*/

/*
* 14字节的以太网包头
*/
typedef struct _ETHDR
{
UCHAR eh_dst[ETH_ALEN]; // 目的MAC地址
UCHAR eh_src[ETH_ALEN]; // 源MAC地址
USHORT eh_type; //
下层协议类型,如IP(ETHERTYPE_IP)、ARP(ETHERTYPE_ARP)等
} ETHDR, *PETHDR;

/*
* 28字节的ARP头
*/
typedef struct _ARPHDR
{
USHORT ar_hrd; // 硬件地址类型,以太网中为ARPHRD_ETHER
USHORT ar_pro; // 协议地址类型,ETHERTYPE_IP
UCHAR ar_hln; // 硬件地址长度,MAC地址的长度为6
UCHAR ar_pln; // 协议地址长度,IP地址的长度为4
USHORT ar_op; //
ARP操作代码,ARPOP_REQUEST为请求,ARPOP_REPLY为响应
UCHAR ar_sha[ETH_ALEN]; // 源MAC地址
ULONG ar_sip; // 源IP地址
UCHAR ar_tha[ETH_ALEN]; // 目的MAC地址
ULONG ar_tip; // 目的IP地址
} ARPHDR, *PARPHDR;

/*
* 20字节的IP头
*/
typedef struct _IPHDR
{
UCHAR h_lenver; // 版本号和头长度(各占4位)
UCHAR tos; // 服务类型
USHORT total_len; // 封包总长度,即整个IP报的长度
USHORT ident; // 封包标识,惟一标识发送的每一个数据报
USHORT frag_and_flags; // 标志
UCHAR ttl; // 生存时间,就是TTL
UCHAR protocol; // 协议,可能是TCP、UDP、ICMP等
USHORT checksum; // 校验和
ULONG saddr; // 源IP地址
ULONG daddr; // 目标IP地址
} IPHDR, *PIPHDR;

/*
* 20字节的TCP头
*/
typedef struct _TCPHDR
{
USHORT srceport; // 16位源端口号
USHORT dstport; // 16位目的端口号
ULONG seq; // 32位序列号
ULONG ack; // 32位确认号
UCHAR dataoffset; // 高4位表示数据偏移
UCHAR flags; // 6位标志位
//FIN - 0x01
//SYN - 0x02
//RST - 0x04
//PSH - 0x08
//ACK - 0x10
//URG - 0x20
//ACE - 0x40
//CWR - 0x80

USHORT window; // 16位窗口大小
USHORT checksum; // 16位校验和
USHORT urgptr; // 16位紧急数据偏移量
} TCPHDR, *PTCPHDR;

/*
* 伪TCP头,计算校验和时使用
*/
typedef struct _PSDTCPHDR
{
ULONG saddr;
ULONG daddr;
char mbz;
char ptcl;
USHORT tcpl;
} PSDTCPHDR, *PPSDTCPHDR;

/*
* 8字节的UDP头
*/
typedef struct _UDPHDR
{
USHORT srcport; // 源端口号
USHORT dstport; // 目的端口号
USHORT len; // 封包长度
USHORT checksum; // 校验和
} UDPHDR, *PUDPHDR;

/*
*伪UDP头,计算校验和时使用
*/
typedef struct _PSDUDPHDR
{
ULONG saddr;
ULONG daddr;
char mbz;
char ptcl;
USHORT udpl;
} PSDUDPHDR, *PPSDUDPHDR;

/*
* 12字节的ICMP头
*/
typedef struct _ICMPHDR
{
UCHAR type; //类型
UCHAR code; //代码
USHORT checksum; //校验和
USHORT id; //标识符
USHORT sequence; //序列号
ULONG timestamp; //时间戳
} ICMPHDR, *PICMPHDR;

/*
* 6字节的PPPOE头+2字节协议
*/
typedef struct _PPPOEHDR
{
UCHAR ver_type; //版本+类型 一般为0x11
UCHAR code; //编码
USHORT sessionid; //session id
USHORT len; //长度
USHORT protocol; //协议
} PPPOEHDR, *PPPPOEHDR;

5/19/2010

时钟的指针

几个关于时钟的问题:

  1. 随便给你一个时间,比如9点25分,如何计算时针、分针之间的角度?
  2. 在24小时之中,时钟的时针、分针和秒针完全重合在一起的时候有几次?都分别是什么时间?你怎样算出来的?
  3. 有时候时针分针互换后合理的时间(比如12:00),但有时候不行(比如3:00),24小时中有多少次可以互换的机会?

思路:

分针一分钟转过的角度为 360/60 = 6
时针一小时转过的角度为 360/12 = 30
时针一分钟转过的角度为 360/12/60 = 0.5
x时y分,时针与分针之间的夹角为 |x*30 + y*0.5 - y*6|


3次或2次,或者一次,分别为时钟的12点和24点出现
假设时针的角速度是ω(ω=π/6每小时),则分针的角速度为12ω,秒针的角速度为72ω。
分针与时针再次重合的时间为t,则有12ωt-ωt=2π,t=12/11小时,换算成时分秒为1小时5分27.3秒,显然秒针不与时针分针重合,同样可以算出其它10次分针与时针重合时秒针都不能与它们重合。只有在正12点和24点时才会重合。 

4/01/2010

[GNOME]OAFIID:Gnome_ClockApplet

前几天遇到一个奇怪的问题,Gnome-panel 上显示时间的Clock 不见了,我从"Add to Panel"重新添加Clock 则报错:"OAFIID:Gnome_ClockApplet",我用的是Gentoo,自然想当然的运行revdep-rebuild,但rebuild 之
后问题依旧,上网搜了一下,也没有具体给出解决办法。于是搜ClockApplet,终于找到Clock 程序的配置文件
:/usr/lib/bonobo/servers/GNOME_ClockApplet_Factory.server,打开后,第三行指出了具体的库文件:location="/usr/lib/gnome-panel/libclock-applet.so",这下就好办了。

ldd /usr/lib/gnome-panel/libclock-applet.so

果然,大部分链接都没问题,但出现以下结果:
    libssl3.so.12 => not found
    libsmime3.so.12 => not found
    libnssutil3.so.12 => not found
    libnss3.so.12 => not found
   
然后运行: qfile libssl3.so.12 libsmime3.so.12 libnssutil3.so.12 libnss3.so.12

dev-libs/nss (/usr/lib/libsmime3.so.12)
dev-libs/nss (/usr/lib/libnssutil3.so.12)
dev-libs/nss (/usr/lib/libnss3.so.12)
dev-libs/nss (/usr/lib/libssl3.so.12)

这样就找出了有问题的库文件对应的包名称,赶紧 emerge -q dev-libs/nss 吧,完成之后再次添加Clock 程
序就正常了 :-)

3/26/2010

PHY 与 MAC

网卡工作在OSI model 的最后两层,物理层(Physical Layer )和数据链路层(Data Link Layer)。

物理层的芯片称之为PHY。物理层定义了数据传送 与接收所需要的电与光信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。

以太网卡中数据链路层的芯片称之为MAC控制器, 数据链路层则提供寻址机构、数据帧的构建、数据差错检查、传送控制、向网络层提供标准的数据接口等功能。

MAC和PHY之间的关系是PCI总线接MAC总 线,MAC接PHY,PHY接网线(当然也不是直接接上的,还有一个变压装置),很多网卡的这两个部分是做到一起的。

PHY和MAC之间互连的界面是IEEE定义的标准:MII/GigaMII(Media Independed Interfade,介质独立界面)。MII界面传递了网络的所有数据和数据的控制。

参考:http://en.wikipedia.org/wiki/PHY_%28chip%29

3/09/2010

公元纪年换算成花甲纪年

老祖宗的东西,别忘了。

  公元纪年与花甲纪年之间有着固定的对应关系,根据其对应关系可以发现一定规律,找出换算方法。
花甲由十天干和十二地支两部分组成,那么我们换算的过程也分两步。在此之前请先记住一个中国人 很敏感的数字"4"。
  
第一步:确定天干。找出将换算成花甲纪年的公元年份的尾数,如1982年尾数为2,1984年 尾数为4。那么尾数
  有0至9共十个数字,正好和天干数目相等。将4与甲对应、5与乙对应、6与丙对应……0与庚对 应、1与辛对应、
  2与壬对应、3与癸对应,可确定天干。

第二步:确定地支。我们将公元年份除以12取余数,可得出0至11共十二个数字,正好与地支数 目相等。将4与
  子对应、5与丑对应、6与寅对应……10与午对应、11与未对应、0与申对应、1与酉对应、2 与戌对应、3与亥对
  应,可确定地支。
  如1982年尾数为2,除以12余2,为壬戌年;1984年尾数为4,除以12余4,为甲子 年;2038年尾数为8,除以12余
  10,为戊午年。

3/02/2010

udev 升级到151之惊魂记

昨天我的笔记本升级系统,顺便把udev 升级到151,重启机器之后hda 设备找不到了,ls /dev/hd* 也没东西,顿时一惊,硬盘没mount 上来,我啥也做不了啊,怎么办?心想应该是udev-151搞的鬼,于是在另外一台机器上搜索udev-151的ChangeLog, 才知道udev-151 remove remaining support for CONFIG_SYSFS_DEPRECATED,再检查我的笔记本的kernel config 中CONFIG_SYSFS_DEPRECATED 选项,居然还是选中的,赶紧去掉重新编译,可是 boot 分区没办法mount 啊,怎么把这个编译出来的新kernel 复制过去呢? 找到一张linux 启动光盘,然后mount 这个boot 分区不就OK 了?我正是这么做的,之后就很顺利了,现在笔记本又启动正常了 :D

2/10/2010

emerge error: "libGL.la" No such file or directory

今天系统sync 之后发行ibus 和ibus-pinyin都有更新了,于是开始更新ibus,谁知编译到一半说找不到libGL.la,这是哪个包里面的呢?
运行:qfile libGL.so
结果:media-libs/mesa (/usr/lib/opengl/xorg-x11/lib/libGL.so)

于是重新emerge -q media-libs/mesa,结果还是不行,在网上搜了一圈没解决问题,于是到mesa 的portage 目录一看,该 media-libs/mesa/files/lib 下面有:
libGL.la和 libGLU.la 两个文件,原来libGL.la 这个文件藏 在这儿,唉!~

估计是安装media-libs/mesa的脚本出问题了,忘记复制libGL.la 到/usr/lib/下面了。





1/22/2010

无线网络安全问题

今天在网上搜wpa_supplicant 以及 AP 的加密方式等资料,发现网上有很多讲破解无线网络的文档,其中提到了破解需要的工具,这里记录一下:

系统: BackTrack
网卡:卡王(台湾Wifly-City的产品)
AP: SMC-WTVG(选用这款的原因是便携,而且功能是非常强大,结合无线路由器(54M)、VoIP网络电话、无线AP、客户端、无线网卡等.)

我还是第一次听说BackTrack 系统,引用 wikipedia(http://en.wikipedia.org/wiki/BackTrack)的说明:

BackTrack is a Linux distribution distributed as a Live CD which resulted from the merger of WHAX (previously Whoppix) and the Auditor Security Collection, which is used for penetration testing.

虽然BackTrack 是Linux 发行版,但是它最大的区别就是它是 Monolithic kernel,翻译成中文是单内核,有空一定要装装看。

交叉编译 openssl

前段时间做过 WiFi的项目,现在功能基本正常,但是目前只支持WEP,对 WPA1/WPA2等不支持,所以需要考虑后续改进的问题。
对于 WPA1/WPA2,在Linux下一般通过wpa_supplicant 来连接AP,而wpa_supplicant 认证过程使用了openssl 的库,因此需要先交叉编译openssl,这里做个笔记 :)

./Configure --prefix=../openssl-arm os/compiler:arm-none-linux-gnueabi-gcc

make 编译之后如果直接make install 的话会报错:
making install in crypto...
make[1]: Entering directory `/wireless/openssl-0.9.8l/crypto'
cp: cannot create regular file `../openssl-arm/include/openssl/crypto.h': No such file or directory
chmod: cannot access `../openssl-arm/include/openssl/crypto.h': No such file or directory
cp: cannot create regular file `../openssl-arm/include/openssl/tmdiff.h': No such file or directory
...

所以我没有 install,反正编译wpa_supplicant 时只需要openssl 的 libssl.a、 libcrypto.a以及 include/openssl/ 下的头文件

1/18/2010

打野战

周末去上庄那边的真人CS部落玩了大半天的真人CS,俗称打野战, 同去的有将近20个人,没想到的是居然来了好几位美女,我们分了两队,玩了两个地图,我第一次玩真人CS,挺海皮的,有位哥们挺猛的,穿的迷彩裤都被他弄成开档了,然后他穿着开裆裤继续战斗 :D 另外,发现狙击枪不太好用,还不如那个可以连发的冲锋枪,下次有机会再去,呵呵

1/08/2010

得到原始shortener url

接上一个主题,说说还原shortener url之后的url。现在有很多shortener url的网站,比如goo.gl, bit.ly等等,如果只是想知道原始的url,则这个网站不错http://untr.im,这里还有一个小脚本:

#!/bin/bash
#filename: getfullurl.sh
URL=$1
if test "x$URL" == ""; then
    exit
fi
curl -q -d "url=$URL" http://untr.im/api/ajax/api | awk -F 'href="' '{print $3}' | awk -F '" rel="' '{print $1}'

运行:
sh getfullurl.sh http://goo.gl/rz2O
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
192   170  170   170    0    22     56      7  0:00:03  0:00:03 --:--:--    81
http://wiki.thc.org/gsm

最好得到 http://wiki.thc.org/gsm

Use the Google URL Shortener API with Python

原文:http://d.hatena.ne.jp/LaclefYoshi/20091216/1260891200

http://goo.gl 是 Google的URL Shortener 服务,类似的有很多,比如 http://tinyurl.com,不过Google URL Shortener没有对外开放,目前只能通过 Google toolbar 和chromium的扩展程序(goo.gl url shortener)才能使用,但是这位日本的朋友通过分析Google toolbar的xpi中js代码,写出了这段python代码,比较佩服他啊,下面贴出他的代码,其中做了一个小小的改动,使得程序可以接收参数。

#!/usr/bin/python
""" Google URL Shortener
 Usage: python goo.gl URL"""

# import struct
import urllib
import simplejson

def usage():
    print __doc__

def _c(vals):
    l = 0
    for val in vals:
        l += val & 4294967295
    return l

def _d(l):
    if l <=  0:
        l += 4294967296
    m = str(l)
    o = 0
    n = False
    for char in m[::-1]:
        q = int(char)
        if n:
            q *= 2
            o += q / 10 + q % 10 # Math.floor(q / 10) + q % 10
        else:
            o += q
        n = not(n)
    m = o % 10
    o = 0
    if m != 0:
        o = 10 - m
        if len(str(l)) % 2 == 1:
            if o % 2 == 1:
                o += 9
            o /= 2
    return str(o) + str(l)

def _e(uri):
    m = 5381
    for char in uri:
        # m = _c([m << 5, m, struct.unpack("B", char)[0]])
        m = _c([m << 5, m, ord(char)])
    return m

def _f(uri):
    m = 0
    for char in uri:
        # m = _c([struct.unpack("B", char)[0], m << 6, m << 16, -1 * m])
        m = _c([ord(char), m << 6, m << 16, -1 * m])
    return m

def _make_auth_token(uri):
    i = _e(uri)
    i = i >> 2 & 1073741823
    i = i >> 4 & 67108800 | i & 63
    i = i >> 4 & 4193280 | i & 1023
    i = i >> 4 & 245760 | i & 16383
    h = _f(uri)
    k = (i >> 2 & 15) << 4 | h & 15
    k |= (i >> 6 & 15) << 12 | (h >> 8 & 15) << 8
    k |= (i >> 10 & 15) << 20 | (h >> 16 & 15) << 16
    k |= (i >> 14 & 15) << 28 | (h >> 24 & 15) << 24
    j = "7" + _d(k)
    return j

def get_short_url(uri, user):
    if user is None:
        user = 'toolbar@google.com'
    token = _make_auth_token(uri)
    opt = 'user='+user+'&'+urllib.urlencode({'url':uri})+'&auth_token='+token
    # print opt
    ggl_url = 'http://goo.gl/api/url'
    res = urllib.urlopen(ggl_url, opt)
    # print res.read()
    short_url =  simplejson.loads(res.read())['short_url']
    return short_url

import sys, os
if __name__ == "__main__":
    #print get_short_url("http://www.aida.t.u-tokyo.ac.jp/", None)
    if len(sys.argv) == 2:
        print get_short_url(sys.argv[1], None)
    else:
        usage()