现代还原卡技术分析之oseasy网络还原卡

现在这个时代计算机发展十分迅速,为了保证公用计算机的使用安全,人们制作了各种各样的还原软件以及还原硬件。但是随着技术的发展,病毒以及骇客也在不断地提升自己的能力,现在的还原卡总是可以破解的。

现在我们以一个具体的例子来看一下。某大学的机房使用了dell的品牌机,上面安装了oseasy的还原卡,使用了金龙卡的计费服务。机器上面搭载了若干的操作系统,这些操作系统是先在一个系统选择菜单里面选择的,一旦选择了操作系统之后其他的操作系统的系统分区就被显示成了未分配的分区,而且无法对那些扇区读写数据。

很显然是还原卡把这些数据隐藏了起来。用xuetr查看驱动模块,发现在系统里面有数个名字叫做pns什么的驱动以及名字叫做磁盘缓冲的驱动被加载,卸载这些驱动,系统就会蓝屏,显然这些就是还原卡的驱动程序。注意这里有一个网络驱动也是还原卡提供的,还原卡为了实现网络还原以及网络控制,以太网的接口位于还原卡上。网络驱动是由操作系统提供的。

显然破解它最简单就是禁用掉这个pci硬件,卸掉驱动。但是进入cmos之后发现被上了管理员密码,使用密码清除工具无法清除密码,只能重置cmos设置。无奈之下就开始研究其他的方式。学校的机器允许u盘启动,但是发现选择u盘启动之后是无法正常的引导,因为机器固定的把硬盘确定在了0x80的磁盘驱动器,而usb设备位于0x81,所以自己写了扇区读取,发现还是不可以,因为还原卡重置了INT 13H中断,没办法,重写13h中断,让它能够实现直接读取磁盘。之后终于能够正常了。但是自己的这些还是不能够适应大硬盘,所以引导老毛桃windows pe,由于pe系统不受还原卡,所以进入pe之后就相当于拥有了系统的主动权,就这样夺权成功

总而言之,这个系统保护的就是在系统引导之前引导自己的mbr,应用自己的功能,实现网络升级,并且把磁盘分区映射,创造临时的活动主要分区,然后他会引导chainloader,引导系统,引导系统之后优先加载自己的驱动,实现磁盘的虚拟化,并且提供网络访问。

具体的技术处于安全因素就不在这篇文章里面透露了。

 

HAL层直接端口IO来绕过atapi层驱动

http://www.jybase.net/windows/20120106743.html

 

关于文件的保护的话题,笔记在前几期的黑防中进行了一些个人的分析,根据IRP的下
发流程,从系统的文件驱动ntfs.sys到atapi.sys的dispatch hook和深度的AtapiStartIo
hook,共记三篇。可以说,从 IRP 发送到文件驱动开始,到下发至 atapi 的 dispatch,以
及 atapi 的一些内部处理都大致讲了一遍。
如果读者没有忘记前面几期的内容,那么应该知道 atapi 后是在 HAL.DLL 中进行端口
IO 的处理了,那么本次笔者就带大家来初步的了解 HAL 中所做的一些工作,以及如何自己
实现直接的端口IO,从而绕过 atapi这层驱动。
如果读者还记得第6期《Atapi的深度 HOOK》一文的内容,那么就会知道IdeReadWrite
这个函数起着“承上启下”的作用,这个函数的“下方”就是IO端口的操作了,而“上方”
则是 atapi 层。那么要了解如何实现直接端口 IO,这个函数对我们来说是至关重要的。首
先这个函数的原型是:
NTSTATUS IdeReadWrite(UCHAR devExt_ach, PVOID  Srb)
下面给出一些关键的汇编代码:

.text:00011239                 push    dword ptr [esi+24h] ; 0x1F7,状态
寄存器
.text:0001123C       call ds:__imp__READ_PORT_UCHAR@4 ; 
.text:00011242                 test    al, al
.text:00011244                 jns     short loc_1124D
……
.text:0001124D loc_1124D:                              ; CODE XREF: 
.text:0001124D                 test    al, 40h         ; 测试第6位(准备
位)
.text:0001124F                 jnz     short loc_11263
……
.text:00011263
.text:00011263 loc_11263:                              ; CODE XREF:
IdeReadWrite(x,x)+3Dj
.text:00011263                 mov     eax, [edi+18h]  ; 设备可以接受命令
.text:00011266                 mov     [esi+84h], eax
.text:0001126C                 mov     eax, [edi+10h]
.text:0001126F                 mov     [esi+88h], eax

.text:00011275                 mov     byte ptr [esi+0C4h], 1
.text:0001127C                 mov     eax, [edi+10h]  ;
Srb.DataTransferLength
.text:0001127F                 add     eax, 1FFh
.text:00011284                 shr     eax, 9          ; 除以 512,扇区大

.text:00011287                 push    eax             ; Value
.text:00011288                 push    dword ptr [esi+10h] ; Port = 0x1F2
.text:0001128B                 call    ebx ; WRITE_PORT_UCHAR(x,x) ; 写
扇区计数寄存器
……
.text:000112A7                 mov     dword ptr [ebp+devExt_ach], eax ;
从 CDB指令中算出起始扇区

.text:000112CA                 push    ecx             ; Value = 块地址
24~27
.text:000112CB                 push    dword ptr [esi+20h] ; Port = 0x1F6
.text:000112CE                 call    ebx ; WRITE_PORT_UCHAR(x,x) ;
WRITE_PORT_UCHAR(x,x)
.text:000112D0                 push    dword ptr [ebp+devExt_ach] ; Value
= 000de1cf
.text:000112D3                 push    dword ptr [esi+14h] ; Prot = 0x1F3
.text:000112D3                                         ; 块地址0~7位
.text:000112D6                 call    ebx ; WRITE_PORT_UCHAR(x,x) ;
WRITE_PORT_UCHAR(x,x)
.text:000112D8                 mov     eax, dword ptr [ebp+devExt_ach]
.text:000112DB                 shr     eax, 8
.text:000112DE                 push    eax             ; Value
.text:000112DF                 push    dword ptr [esi+18h] ; Port = 0x1F4
.text:000112DF                                         ; 块地址8~15位
.text:000112E2                 call    ebx ; WRITE_PORT_UCHAR(x,x) ;
WRITE_PORT_UCHAR(x,x)
.text:000112E4                 mov     eax, dword ptr [ebp+devExt_ach]
.text:000112E7                 shr     eax, 10h
.text:000112EA                 push    eax
.text:000112EB                 push    dword ptr [esi+1Ch] ; Port = 0x1F5
.text:000112EB                                         ; 块地址16~23位
.text:000112EE                 jmp     short loc_1135B
.text:0001135B loc_1135B:                              ; CODE XREF: 
.text:0001135B                 call    ebx ; WRITE_PORT_UCHAR(x,x) ;

 

上面的汇编代码就算是结合注释想理解也很困难。因为它涉及到了IDE接口的一
些技术。在IDE读写时,先要对一些IDE的寄存器进行设置,最后才是调用HAL 中的

WRITE_PORT_xxxx 或者 READ_PORT_xxxx 系列的函数读写数据。下面给出这些 IDE 寄存器的
相关介绍:
1.Task File Registers命令寄存器组 
I/O 地址  读(主机从硬盘读数据)     写(主机数据写入硬盘) 
1F0H    数据寄存器        数据寄存器 
1F1H    错误寄存器(只读寄存器)      特征寄存器 
1F2H    扇区计数寄存器       扇区计数寄存器 

1F3H    扇区号寄存器或LBA块地址0~7    扇区号或LBA 块地址0~7 
1F4H    磁道数低 8位或 LBA块地址 8~15   磁道数低 8位或 LBA块地址8~15 
1F5H    磁道数高 8位或 LBA块地址 16~23  磁道数高8位或LBA块地址 16~23 
1F6H    驱动器/磁头或LBA块地址 24~27   驱动器/磁头或LBA块地址24~27 
1F7H    状态寄存器        命令寄存器 
特殊 Task File Registers的位含义
0x1F6: 7~5位,010,第4位 0 表示主盘,1 表示从盘,3~0位,0
状态寄存器(0x1F7):
  第八位:忙。1表示设备正忙
第七位:准备。1 表示设备可以接受命令
第六位:错误。1 表示写错误发生
第五位:寻址。1表示完成寻道操作
第四位:请求。1 表示请求主机数据传输
第三位:校验。1 表示已校正磁盘
第二位:索引。这个不重要
第一位:错误。1 表示前次命令时发生错误
  命令寄存器(0x1F7)
  0x20为读, 0x30 为写
2.Control/Diagnostic Registers控制/诊断寄存器 
I/O 地址     读        写 
3F6H    交换状态寄存器(只读寄存器)  设备控制寄存器(复位) 
3F7H    驱动器地址寄存器
特殊控制/诊断寄存器的位含义
0x3F6 = 0x80 (0000 1RE0): R=reset, E=0 =enable interrupt
有了这些资料,再加上笔者的注释,不难知道上面的流程:先对设备进行查询是否可以
接受指令,可以则对设备的命令组寄存器进行设置,其中有对SRB 结构中的CDB 结构进行一
些计算,得出LBA 等数据,看过上期文章的读者对这几个结构应该不会陌生。
于是可以仿照这个过程写出我们的初始代码,如下: 
WRITE_PORT_UCHAR(0x3F6, 0x0c);
 WRITE_PORT_UCHAR(0x3F6, 0x08);
 WRITE_PORT_UCHAR(0X1F2, 1);
 WRITE_PORT_UCHAR(0x1F3, 0);
 WRITE_PORT_UCHAR(0X1F4, 0);
 WRITE_PORT_UCHAR(0X1F5, 0);
 WRITE_PORT_UCHAR(0x1F6, 0xE0);

 

关于其中的 1、2 行代码作用分别是重置设备和启用中断。剩下的代码作用是从磁盘的
0 扇区开始读出一个扇区的内容,即MBR。
接下来应该看 IdeReadWrite 剩下的代码了。但是笔者在浏览了 IDA 反汇编出来的代码
后,却在发现 IdeReadWrite 的磁盘读操作分支中只进行一些简单的处理后调用了
WRITER_PORT_UCHAR,之后再调用了 PCIIDEX!BmArm 来启动 DMA 通道,并进行数据的传输,
当然这不是笔者想要的,我们要做的是直接 IO,于是我们只能依靠资料来进行推测并尝试
着去写代码。或许笔者比较幸运,在几次尝试后就成功了。代码如下:
 WRITE_PORT_UCHAR(0x1F7, 0x20);
  while((READ_PORT_UCHAR((PUCHAR)0x1f7)&0xf) != 0x08)
  KeStallExecutionProcessor(0X96);
 READ_PORT_BUFFER_USHORT(0x1F0, (PUSHORT)buffer, 512/2); 
上面的代码笔者解释下。在向 0x1F7 端口写入 0x20 命令(也就是读命令)后,用
READ_PORT_UCHAR命令从0x1F7端口中读出设备的状态,并且比较第四位,从而判断是否已
经完成数据的传输。这里注意,当0x1F7 用做读时,为状态寄存器,当0x1F7用做写时,当
做命令寄存器,在上面给出的 IDE 介绍中也可以看出这一点。如果数据传输完成将会被读出
到 0x1F0 端口处,用READ_PORT_BUFFER_USHORT读取到自己分配的内存区即可。
其中调用 READ_PORT_BUFFER_USHORT时,第一次笔者用了READ_PORT_UCHAR 读出来的数
据是跳着读的,即读出前一位数据后,跳过中间一位数据,再读后一位。笔者百思不得其解,
希望有人能解答。
最后运行的结果,与WinHex读出的 MBR相比较发现是一致的,如图1。
 至此笔者从最初的只是想看看ntfs流程,到 atapi,最后再到端口IO。共计四篇文章,
简单讨论了三个层面对文件读写的响应,不敢说对读者有很大帮助,但只要读者能从这四
篇文章得到一些益处,笔者就满足了。
本文所有代码在XPSP3+WDK中编译通过,并在XPSP3上成功运行。本文只实现了对硬盘
的读操作,并未实现写操作。示例代码也非常的简单,可以说只是提供了思路,并未经过
严格的测试。希望本文起到抛砖引玉的作用,期待更精彩的文章出现。行文仓促,加之硬
件设备复杂,资料少,所以纰漏难免,欢迎批评指正。

 

通过IO口对硬盘绝对扇区读写

http://read.pudn.com/downloads79/sourcecode/hack/crack/301277/%E7%A1%AC%E7%9B%98%E7%9B%B4%E6%8E%A5IO.asm__.htm

通过IO口对硬盘绝对扇区读写2006-09-20 17:18对硬盘进行操作的常用端口是1f0h~1f7h号端口,各端口含义如下:
端口号     读还是写   具体含义
1F0H       读/写      用来传送读/写的数据(其内容是正在传输的一个字节的数据)
1F1H       读         用来读取错误码
1F2H       读/写      用来放入要读写的扇区数量
1F3H       读/写      用来放入要读写的扇区号码
1F4H       读/写      用来存放读写柱面的低8位字节
1F5H       读/写      用来存放读写柱面的高2位字节(其高6位恒为0)
1F6H       读/写      用来存放要读/写的磁盘号及磁头号
                    第7位     恒为1
                    第6位     恒为0
                    第5位     恒为1
                    第4位     为0代表第一块硬盘、为1代表第二块硬盘
                    第3~0位    用来存放要读/写的磁头号
1f7H       读         用来存放读操作后的状态
                    第7位     控制器忙碌
                    第6位     磁盘驱动器准备好了
                    第5位     写入错误
                    第4位     搜索完成
                    第3位     为1时扇区缓冲区没有准备好
                    第2位     是否正确读取磁盘数据
                    第1位     磁盘每转一周将此位设为1,
                    第0位     之前的命令因发生错误而结束
         写         该位端口为命令端口,用来发出指定命令
                    为50h     格式化磁道
                    为20h     尝试读取扇区
                    为21h     无须验证扇区是否准备好而直接读扇区
                    为22h     尝试读取长扇区(用于早期的硬盘,每扇可能不是512字节,而是128字节到1024之间的值)
                    为23h     无须验证扇区是否准备好而直接读长扇区
                    为30h     尝试写扇区
                    为31h     无须验证扇区是否准备好而直接写扇区
                    为32h     尝试写长扇区
                    为33h     无须验证扇区是否准备好而直接写长扇区
注:当然看完这个表你会发现,这种读写端口的方法其实是基于磁头、柱面、扇区的硬盘读写方法,不过大于8G的硬盘的读写方法也是通过端口1F0H~1F7H来实现的^_^

一个通过对硬盘输入输出端口操作来读写硬盘的实例
让我们来看一个关于INT13H读写硬盘程序实例。在例子中详细说明了硬盘的读写操作所用到的端口,并且把通过INT13H读出的主引导区得到的数据和通过输入输出读主引导区得到的数据进行比较,从而证实这两种操作功能相同,程序片段如下:

mov dx,1f6h ; 要读入的磁盘号及磁头号
mov al,0a0h ;磁盘0,磁头0
out dx,al

mov dx,1f2h ;要读入的扇区数量
mov al,1 ;读一个扇区
out dx,al

mov dx,1f3h ;要读的扇区号
mov al,1 ;扇区号为1
out dx,al

mov dx,1f4h ;要读的柱面的低8位
mov al,0 ; 柱面低8位为0
out dx,al

mov dx,1f5h ; 柱面高2位
mov al,0 ; 柱面高2位为0(通过1F4H和1F5H端口我们可以确定
; 用来读的柱面号是0)
out dx,al

mov dx,1f7h ;命令端口
mov al,20h ; 尝试读取扇区
out dx,al
still_going:
in al,dx
test al,8 ;扇区缓冲是否准备好
jz still_going ;如果扇区缓冲没有准备好的话则跳转,直到准备好才向下执行。

mov cx,512/2 ;设置循环次数(512/2次)
mov di,offset buffer
mov dx,1f0h ;将要传输的一个字节的数据
rep insw ;传输数据

; ——

mov ax,201h ;以下是用INT13H读硬盘的0磁头、0柱面、1扇区
mov dx,80h
mov cx,1
mov bx,offset buffer2
int 13h

mov cx,512 ;以下部分用来比较2种方法读出的硬盘数据
mov si,offset buffer
mov di,offset buffer2
repe cmpsb
jne failure
mov ah,9
mov dx,offset readmsg
int 21h
jmp good_exit
failure:
mov ah,9
mov dx,offset failmsg
int 21h
good_exit: ;以下部分用来结束程序
mov ax,4c00h ;退出程序
int 21h

readmsg db ‘The buffers match. Hard disk read using ports.$’
failmsg db ‘The buffers do not match.$’
buffer db 512 dup (‘V’)
buffer2 db 512 dup (‘L’)

附:
我的“硬盘绝对扇区检测”功能代码:
平台:Fedora Core 5
NASM version 0.98.39
gcc 版本 4.1.0 20060304 (Red Hat 4.1.0-3)
编译命令:
由于有端口读写,所以需要在root下运行
nasm -f elf *.asm
gcc *.o
./a.out
代码:
global main
extern printf
extern ioperm
section .data
dmsg db ‘The buffers match. The sector is good.’,0Dh,0Ah,0
failmsg db ‘The buffers do not match. The sector is bad.’,0Dh,0Ah,0
buf_d times 512 db ‘V’
ct1 db ‘buf_director’,0Dh,0Ah,0
buf_s times 512 db ‘K’
ct2 db ‘buf_source’,0Dh,0Ah,0
buf_g times 512 db ‘G’
ct3 db ‘buf_ghost’,0Dh,0Ah,0
disk db 0b0h ;要读入的磁盘号及磁头号
;第7位 恒为1
;第6位 恒为0
;第5位 恒为1
;第4位 为0代表第一块硬盘、为1代表第二块硬盘
;第3~0位 用来存放要读/写的磁头号
secnum db 1 ;要读入的扇区数量,读一个扇区
secno db 1 ;要读的扇区号,扇区号为1
cylin_l db 0 ;要读的柱面的低8位,柱面低8位为0
cylin_h db 0 ;柱面高2位,柱面高2位为0
section .text
main:
mov ax,ds
mov es,ax

push word 1 ;打开 1f0h-1f7h 端口的读写权限
push dword 08h
push dword 1f0h
call ioperm
add esp,10 ;清空栈

push dword buf_g ;备份数据
pop eax
mov edi,eax
call read
push dword buf_g ;打印
call printf
pop eax

push dword buf_s ;写入数据
pop eax
mov esi,eax
call write
push dword buf_s ;打印
call printf
pop eax

push dword buf_d ;读出数据
pop eax
mov edi,eax
call read
push dword buf_d ;打印
call printf
pop eax

push dword buf_g ;恢复数据
pop eax
mov esi,eax
call write

mov cx,512 ;比较数据,测试是否坏道
push dword buf_d
pop eax
mov esi,eax
push dword buf_s
pop eax
mov edi,eax
repe cmpsb
jne failure

push dword dmsg ;成功,无坏块
call printf
pop eax
jmp exit
failure:
push dword failmsg ;失败,坏块
call printf
pop eax
exit:
ret
read:
mov dx,1f6h ;要读入的磁盘号及磁头号
mov al,[disk]
out dx,al

mov dx,1f2h ;要读入的扇区数量
mov al,[secnum]
out dx,al

mov dx,1f3h ;要读的扇区号
mov al,[secno]
out dx,al

mov dx,1f4h ;要读的柱面的低8位
mov al,[cylin_l]
out dx,al

mov dx,1f5h ;柱面高2位
mov al,[cylin_h]
out dx,al

mov dx,1f7h ;命令端口
mov al,20h ; 尝试读取扇区
;1f7H 读 用来存放读操作后的状态
;第7位 控制器忙碌
;第6位 磁盘驱动器准备好了
;第5位 写入错误
;第4位 搜索完成
;第3位 为1时扇区缓冲区没有准备好
;第2位 是否正确读取磁盘数据
;第1位 磁盘每转一周将此位设为1,
;第0位 之前的命令因发生错误而结束
;写 该位端口为命令端口,用来发出指定命令
;为50h 格式化磁道
;为20h 尝试读取扇区
;为21h 无须验证扇区是否准备好而直接读扇区
;为22h 尝试读取长扇区(用于早期的硬盘,每扇可能不是512字节,而是128字节到1024之间的值)
;为23h 无须验证扇区是否准备好而直接读长扇区
;为30h 尝试写扇区
;为31h 无须验证扇区是否准备好而直接写扇区
;为32h 尝试写长扇区
;为33h 无须验证扇区是否准备好而直接写长扇区
out dx,al
still_going:
in al,dx
test al,8 ;扇区缓冲是否准备好
jz still_going

mov cx,512/2 ;设置循环次数(512/2次)
mov dx,1f0h ;将要传输的一个字节的数据
rep insw ;传输数据
ret

write:
mov dx,1f6h ;要写入的磁盘号及磁头号
mov al,[disk]
out dx,al

mov dx,1f2h ;要写入的扇区数量
mov al,[secnum]
out dx,al

mov dx,1f3h ;要写的扇区号
mov al,[secno]
out dx,al

mov dx,1f4h ;要写的柱面的低8位
mov al,[cylin_l]
out dx,al

mov dx,1f5h ;柱面高2位
mov al,[cylin_h]
out dx,al

mov dx,1f7h ;命令端口
mov al,30h ;尝试写入扇区
out dx,al
still_going_2:
in al,dx
test al,40h ;第6位 磁盘驱动器是否准备好了
jz still_going_2

write_again:
mov cx,512/2 ;设置循环次数(512/2次)
mov dx,1f0h ;将要传输的一个字节的数据
rep outsw ;传输数据

; in al,dx
; test al,20h ;第5位 写入错误
; jz write_again
ret

附2:
硬盘绝对扇区检测程序代码–shell

#!/bin/bash
#$1 起始扇区号,扇区号LBA从 0 开始计
#$2 待测试扇区数
#$3 测试次数

if [ $# -ne 3 ]
then
echo “Useage: ./testdisk StartSectorNo SectorNum TestTimes”
exit $E_BADARGS
fi
let “z = 65” #初始写 ‘A’

a=1
while [ $a -le “$3” ]
do
a=$(($a+1))
######################生成用来测试写入的文件#########################################
let “t = $z / 64”
let “t = $t * 10 + ( $z % 64 / 8 ”
let “t = t * 10 + $z % 8”
rm -f tmp*
touch tmp
echo -ne “$t” >> ./tmp
let “z += 1”
if [ $z = 91 ]
then
let “z = 65”
fi
let “i = 1”
while [ $i -ne 10 ]
do
touch tmp2
cat ./tmp >> ./tmp2
cat ./tmp >> ./tmp2
mv tmp2 tmp
let “i += 1”
done
mv tmp tmp2
let “i = 0”
touch tmp
while [ $i -ne $2 ]
do
cat ./tmp2 >> ./tmp
let “i += 1”
done
############################开始测试写入&&读出&&比较####################################
dd if=./tmp of=/dev/hdb bs=512 count=$2 seek=$1
dd if=/dev/hdb of=./tmp_b bs=512 count=$2 skip=$1
if diff tmp tmp_b >> log
then
echo “***the sector from $1 to $[$1+$2-1] is good*****At the test times: $[$a-1]**********”
else
let “b = 0”
while [ $b -le $(($2-1)) ]
do
b=$(($b+1))
dd if=tmp2 of=/dev/hdb bs=512 count=1 seek=$[$1+$b-1]
dd if=/dev/hdb of=./tmp_s bs=512 count=1 skip=$[$1+$b-1]
if diff tmp2 tmp_s >> log
then
echo “*******the sector $[$1+$b-1] is good*****At the test time: $[$a-1]************************”
else
echo “*******the sector $[$1+$b-1] is bad******At the test time: $[$a-1]************************”
fi
done
fi
done

android入门整合(1.5):Android NDK环境搭建

基于 Android NDK 的学习之旅—–环境搭建

 

工欲善其事必先利其器 , 下面介绍下 Eclipse SDK NDK Cygwin CDT 集成开发环境的搭建。

1、Android 开发环境搭建

Android开发环境搭建不是重点,相信看此文章的很多人都已经搭建成功,这里随便概述性的说说。

1) 下载 JDK

2) 下载 Eclipse

3) 下载 Android SDK

4) 启动Eclipse , 安装 ADT

 

2、下载安装Android NDK

我使用的NDK版本为r5

Google 出的最新NDK 为 r6 下载地址为

http://developer.android.com/sdk/ndk/index.html

 

3、下载安装cygwin

由于NDK编译代码时必须要用到make和gcc,所以你必须先搭建一个linux环境, cygwin是一个在windows平台上运行的unix模拟环境,它对于学习unix/linux操作环境,或者从unix到windows的应用程序移植,非常有用。通过它,你就可以在不安装linux的情况下使用NDK来编译C、C++代码了。下面我们一步一步的安装cygwin吧。

(安装的时候忘记截图了)

首先,你得先跑到http://www.cygwin.com下载setup.exe

1、 然后双击运行吧,运行后你将看到安装向导界面:

2、 点击下一步

此时让你选择安装方式:

1)Install from Internet:直接从Internet上下载并立即安装(安装完成后,下载好的安装文件并不会被删除,而是仍然被保留,以便下次再安装)。

2)Download Without Installing:只是将安装文件下载到本地,但暂时不安装。

3)Install from Local Directory:不下载安装文件,直接从本地某个含有安装文件的目录进行安装。

3、选择第一项,然后点击下一步:

4、选择要安装的目录,注意,最好不要放到有中文和空格的目录里,似乎会造成安装出问题,其它选项不用变,之后点下一步:

5、上一步是选择安装cygwin的目录,这个是选择你下载的安装包所在的目录,默认是你运行setup.exe的目录,直接点下一步就可以:

6、此时你共有三种连接方式选择:

1) Direct Connection:直接连接。

2) Use IE5 Settings:使用IE的连接参数设置进行连接。

3) Use HTTP/FTP Proxy:使用HTTP或FTP代理服务器进行连接(需要输入服务器地址、端口号)。

用户可根据自己的网络连接的实情情况进行选择,一般正常情况下,均选择第一种,也就是直接连接方式。然后再点击“下一步”,

7、 这是选择要下载的站点,我用的是http://mirrors.kernel.org,速度感觉还挺快,选择后点下一步

8、 此时会下载加载安装包列表

9、Search是可以输入你要下载的包的名称,能够快速筛选出你要下载的包。那四个单选按钮是选择下边树的样式,默认就行,不用动。View默认是Category,建议改成full显示全部包再查,省的一些包被隐藏掉。左下角那个复选框是是否隐藏过期包,默认打钩,不用管它就行,下边开始下载我们要安装的包吧,为了避免全部下载,这里列出了后面开发NDK用得着的包:autoconf2.1、automake1.10、binutils、gcc-core、gcc- g++、gcc4-core、gcc4-g++、gdb、pcre、pcre-devel、gawk、make共12个包

10、 然后开始选择安装这些包吧,点skip,把它变成数字版本格式,要确保Bin项变成叉号,而Src项是源码,这个就没必要选了。

11、 下面测试一下cygwin是不是已经安装好了。

运行cygwin,在弹出的命令行窗口输入:cygcheck -c cygwin命令,会打印出当前cygwin的版本和运行状态,如果status是ok的话,则cygwin运行正常。

然后依次输入gcc –version,g++ –version,make –version,gdb –version进行测试,如果都打印出版本信息和一些描述信息,非常高兴的告诉你,你的cygwin安装完成了!

4、配置NDK环境变量

1、 首先找到cygwin的安装目录,找到一个home<你的用户名>.bash_profile文件,我的是:E:cygwinhomeAdministrator.bash_profile,(注意:我安装的时候我的home文件夹下面神马都没有,解决 的办法:首先打开环境变量,把里面的用户变量中的HOME变量删掉,在E:cygwinhome文件夹下建立名为Administrator的文件夹(是用户名),然后把E:cygwinetcskel.bash_profile拷贝到该文件夹下)。

2、 打开bash_profile文件,添加NDK=/cygdrive/<你的盘符>/<android ndk 目录>例如:NDK=/cygdrive/e/android-ndk-r5

export NDK

NDK这个名字是随便取的,为了方面以后使用方便,选个简短的名字,然后保存

3、打开cygwin,输入cd $NDK,如果输出上面配置的/cygdrive/e/android-ndk-r5信息,则表明环境变量设置成功了。

5、用NDK来编译程序

1、 现在我们用安装好的NDK来编译一个简单的程序吧,我们选择ndk自带的例子hello-jni,我的位于E:android-ndk-r5sampleshello-jni(根据你具体的安装位置而定),

2、 运行cygwin,输入命令cd /cygdrive/e/android-ndk-r5/samples/hello-jni,进入到E:android-ndk-r5sampleshello-jni目录。

3、 输入$NDK/ndk-build,执行成功后,它会自动生成一个libs目录,把编译生成的.so文件放在里面。($NDK是调用我们之前配置好的环境变量,ndk-build是调用ndk的编译程序)

4、 此时去hello-jni的libs目录下看有没有生成的.so文件,如果有,你的ndk就运行正常啦!

6、在eclipse中集成c/c++开发环境

1、 装Eclipse的C/C++环境插件:CDT,这里选择在线安装。

首先登录http://www.eclipse.org/cdt/downloads.php,找到对应你Eclipse版本的CDT插件的在线安装地址。

2、 然后点Help菜单,找到Install New Software菜单

3、 点击Add按钮,把取的地址填进去,出来插件列表后,选Select All,然后选择下一步即可完成安装

4、 安装完成后,在eclispe中右击新建一个项目,如果出现了c/c++项目,则表明你的CDT插件安装成功啦!

7、配置C/C++的编译器

1、 打开eclipse,导入ndk自带的hello-jni例子,右键单击项目名称,点击Properties,弹出配置界面,之后再点击Builders,弹出项目的编译工具列表,之后点击New,新添加一个编译器,点击后出现添加界面,选择Program,点 击OK

2、出现了添加界面,首先给编译配置起个名字,如:C_Builder

设置Location为<你cygwin安装路径>binbash.exe程序,例如:E:cygwinbinbash.exe,设置WorkingDirectory为<你cygwin安装路径>bin目录,例如:E:cygwinbin

设置Arguments为

–login -c “cd /cygdrive/I/JavaWorkSpace/Blog/NDK_02&& $NDK/ndk-build”

 

上面的配置中 /cygdrive/I/JavaWorkSpace/Blog/NDK_02是你当前要编译的程序的目录,$NDK是之前配置 的ndk的环境变量,这两个根据你具体的安装目录进行配置,其他的不用变,Arguments这串参数实际是 给bash.exe命令行程序传参数,进入要编译的程序目录,然后运行ndk-build编译程序

3、接着切换到Refresh选项卡,给Refresh resources upon completion打上钩

 

4、然后切换到Build Options选项卡,勾选上最后三项

 

5、之后点击Specify Resources按钮,选择资源目录,勾选你的项目目录即可

 

6、 最后点击Finish,点击OK一路把刚才的配置都保存下来,注意:如果你配置的编译器在其它编译器下边,记得一定要点Up按钮,把它排到第一位,否则C代码的编译晚于Java代码的编译,会造成你的C代码要编译两次才能看到最新的修改

7、 这一路下来肯定很累了吧,现在再次恭喜你,编译配置也配置完成啦,现在来测试一下是否可以自动编译呢,打开项目jni目录里的hello-jni.c文件把提示Hello from JNI!改成其他的文字:如:Hello,My name is alex.,然后再模拟器中运行你的程序,如果模拟器中显示了你最新修改的文字,那么Congratulations!你已经全部配置成功啦!

 

文章参考 http://yueguc.iteye.com/blog/946724

PHP OOP快速入门

http://www.phpchina.com/archives/view-11749-1.html

面向对象编程(OOP)是我们编程的一项基本技能,PHP4对OOP提供了良好的支持。如何使用OOP的思想来进行PHP的高级编程,对于提高PHP编程能力和规划好Web开发构架都是非常有意义的。下面我们就通过实例来说明使用PHP的OOP进行编程的实际意义和应用方法。

我们通常在做一个有数据库后台的网站的时候,都会考虑到程序需要适用于不同的应用环境。和其他编程语言有所不同的是,在PHP中,操作数据库的是一系列的具体功能函数(如果你不使用ODBC接口的话)。这样做虽然效率很高,但是封装却不够。如果有一个统一的数据库接口,那么我们就可以不对程序做任何修改而适用于多种数据库,从而使程序的移植性和跨平台能力都大大提高。

在PHP中要完成OOP,需要进行对象封装,也就是编写类。我们可以通过生成一个新的SQL类实现对数据库的简单封装。例如:

< ?
class SQL
{
var $Driver; //实际操作的数据库驱动子类
var $connection; //共用的数据库连接变量
function DriverRegister($d)
{
if($d!=””)
{
$include_path = ini_get(“include_path”);  字串8
$DriverFile = $include_path.”/”.$d.”.php”;
//驱动的存放路径必须在PHP.ini文件中设定的INCLUDE_PATH下
if( file_exists( $DriverFile)) //查找驱动是否存在
{
include($DriverFile);
$this->Driver = new $d();
// 根据驱动名称生成相应的数据库驱动类
return true;
}
}
return false; //注册驱动失败
}
function Connect($host,$user,$passwd,$database)//连接数据库的函数
{
$this->Driver->host=$host;
$this->Driver->user=$user;
$this->Driver->passwd=$pas
swd;
$this->Driver->database=$d
atabase;
$this->connection = $this->Driver->Connect();
}
function Close()//关闭数据库函数
{
$this->Driver->close($this->connection);
}
function Query($queryStr)//数据库字符串查询函数
{  字串5
return $this->Driver->query($queryStr,$this->connection);
}
function getRows($res)//查找行
{
return $this->Driver->getRows($res);
}
function getRowsNum($res)//取得行号
{
return $this->Driver-> getRowsNum ($res);
}
}
? >

我们以操作MySQL数据库为例。我们写一个数据库驱动类MySQL,在该类中,我们把有关MySQL数据库操作的函数都做进一步的封装。把包含该类,文件名为MySQL.php的文件放在PHP的系统 include_path下,就可以正常地使用了。注意编写数据库驱动文件时,文件名应和类名保持一致。

< ?
Class MySQL
{
var $host;
var $user;
var $passwd;
var $database;
function MySQL() //利用构造函数实现变量初始化
{
$host = “”;
$user = “”;
$passwd = “”;
$database = “”;

字串8
}
function Connect()
{
$conn = MySQL_connect($this->host, $this->user,$this->passwd) or
die(“Could not connect to $this->host”);
MySQL_select_db($this->database,$conn) or
die(“Could not switch to database $this->database;”);
return $conn;
}
function Close($conn)
{
MySQL_close($conn);
}

function Query($queryStr, $conn)
{
$res =MySQL_query($queryStr, $conn) or
die(“Could not query database”);
return $res;
}
function getRows($res)
{
$rowno = 0;
$rowno = MySQL_num_rows($res);
if($rowno>0)
{
for($row=0;$row<$rowno;$row++)
{
$rows[$row]=MySQL_fetch_row($res);
}
return $rows;  字串9
}
}
function getRowsNum($res)
{
$rowno = 0;
$rowno = mysql_num_rows($res);
return $rowno;
}
}
? >
同样我们要封装其他的“数据库驱动”到我们的SQL类中,只需要建立相应的类,并以同名命名驱动文件,放到PHP的include目录就可以了。

完成封装以后,就可以在PHP中按照OOP的思想来实现对数据库的编程了。

< ?
Include(“SQL.php”);
$sql = new SQL; //生成新的Sql对象
if($sql-> DriverRegister(“MySQL”)) //注册数据库驱动
{
$sql->Connect(“localhost”,”root”,””,”test”);
$res=$sql->query(“select * from test”); //返回查询记录集
$rowsnum = $sql->getRowsNum($res);
if($rowsnum > 0)
{
$rows = $sql->getRows($res);
foreach($rows as $row) //循环取出记录集内容
{  字串4
foreach($row as $field){
print $field;}
}
}
$sql->Close();
}
? >

在实际应用中,我们还可以根据实际需求对各种对象类做进一步扩展。在PHP中,还提供了一系列复杂的OOP方法,例如继承,重载,引用,串行化等等。充分调动各种方法并灵活运用,就能够使你的网站更合理和结构化,开发和维护也更容易。

android入门整合(1):搭建android开发环境

注意:这个教程似乎是已经过时的了,本人亲测,现在google的android开发的网站可以直接访问,并且下载的ADK直接包含了整合好的java的IDE,所以只需要提前安装java就可以了

 

原文链接:http://blog.csdn.net/Mac_cm/archive/2009/01/06/3720492.aspx

 

搭建Android开发环境

1 下载Android SDK

http://code.google.com/android/download.html

这是官方网址,进入后跟着流程走,选择适合于自己平台(这里是Windows)的SDK包下载。下载后直接解压就可以使用了。

为了在DOS控制台中直接使用SDK的工具,可以将SDK的目录添加到Windows的path环境变量中:在桌面上右击“我的电脑”,依次点击【属性】>【高级】>【环境变量】。双击【系统变量】里面的Path项,将Android SDK中tools目录的完整路径添加到这里。

 

2 下载JDK6

http://java.sun.com/javase/downloads/index.jsp

下载并安装Java开发包。

 

3 下载Eclipse3.4.1

http://www.eclipse.org/downloads/

在“Eclipse Packages”标签页中选择“Eclipse Classic3.4.1”进行下载。这是目前最新的版本。

对于Eclipse来说,直接解压之后就可以使用。

 

4 下载Eclipse的Android ADT插件

许多教程在这一步都是通过Eclipse自身的update功能进行下载:

启动Eclipse,选择【Help】 > 【Soft Updates】 > 【Find and Install…】

选择“Available Software”标签页,点击【Add Site…】按键。添加update站点:https://dl-ssl.google.com/android/eclipse/

这时窗口中新增了“https://dl-ssl.google.com/android/eclipse/”项,选中该项,点击【Install…】按键即可下载。

注:许多国内的网友都无法完成这样的升级,通常是进行到一半就没有任何反映了(其他插件,例如pydev也是这样)。

 

没关系,我们直接到Android官网去下载这个ADT插件:

http://code.google.com/android/adt_download.html

下载完成后解压,将“features”和“plugins”目录中的文件拷贝到Eclipse的对应目录中就可以了。

 

重启Eclipse,进行Android SDK设置:

选择【Windows】 > 【Preferences…】打开编辑属性窗口

选择Android属性面板

加入Android SDK的目录(点击【Browse…】进行选择,这里是“android-sdk-windows-1.0_r1”所在的目录)。

 

设置Eclipse的Java JDK属性设置

选择【Window】>【Preferences…】打开编辑属性窗口

选择Java属性面板

选择Java编译器为6.0

点击Apply,和OK。

注:这是大多数教材提到的步骤。可是很奇怪,在我安装的时候并没有经历这样一个步骤(实际上,根本就没有“Java编译器为6.0”这个选项)。

我这里的Eclipse版本为最新的3.4.1,可能与它有关。

 

创建一个Android工程

搭建好开发环境之后,我们来创建一个Hello World工程,体验一下Android的开发。

1 选择【File】>【New】>【Project】

2 选择【Android】>【Android Project】,点击【Next】

3 创建一个新的Android工程

Project name(在计算机中存储工程的目录名):                       HelloWorld

Package name(包名,请参考Java相关的概念):                     com.china.hello

Activity name(UI界面窗口的类名,从Activity继承而来):      HelloChina

Application name(应用的标题名字):                                       test Android

 

这样一个Android的工程就创建完毕了。

在Package Explorer窗口中选择【src】>【com.china.hello】>【HelloChina.java】文件,编辑代码:

package com.china.hello;

import android.app.Activity;

import android.os.Bundle;

import android.widget.TextView;

public class HelloChina extends Activity {

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle saveInstanceState) {

        super.onCreate(saveInstanceState);

        //setContentView(R.layout.main);

        TextView tv = new TextView(this);

        tv.setText(“helloWorld”);

        setContentView(tv);

    }

}

 

运行

在“Run As”窗口中选择“Android Application”

os-easy boot引导分析(一):反汇编MBR

不多说,win-hex先把有用的复制出来

回来之后ida开始反汇编

反汇编的时候ida提示不知道入口,直接分析就可以,文件时直接转载在7c00地址的

分析完一部分之后ida停止了,因为它不知道正确的跳转,人工分析,发现相当于就是向下继续执行,让ida继续分析。

人工分析代码,已经标上了注释,代码贴在下面