星期三, 9月 10, 2008

重新啟動WinCE系統

WinCE系統若想要重新啟動,沒有.NET的Managed函數可用,須倚靠 Coredll.dll的KernelIoControl完成,以下是用Managed包裝後的重啟函數,使用方法很簡單,直接呼叫ResetSystem()即可:

Private Const FILE_DEVICE_HAL As Integer = &H101
Private Const METHOD_BUFFERED As Integer = 0 Private Const FILE_ANY_ACCESS As Integer = 0
Private Function CTL_CODE( _ ByVal DeviceType As Integer, _ ByVal Func As Integer, _ ByVal Method As Integer, _ ByVal Access As Integer) As Integer
Return (DeviceType << 16) Or (Access << 14) Or (Func << 2) Or Method
End Function
Declare Function KernelIoControl Lib "CoreDll.dll" _ (ByVal dwIoControlCode As Integer, _ ByVal lpInBuf As IntPtr, _ ByVal nInBufSize As Integer, _ ByVal lpOutBuf As IntPtr, _
ByVal nOutBufSize As Integer, _ ByRef lpBytesReturned As Integer _ ) As Integer
Private Function ResetSystem() As Integer
Dim bytesReturned As Integer = 0 Dim IOCTL_HAL_REBOOT As Integer = CTL_CODE(FILE_DEVICE_HAL, _ 15, METHOD_BUFFERED, FILE_ANY_ACCESS)
Return KernelIoControl(IOCTL_HAL_REBOOT, IntPtr.Zero, 0, _
IntPtr.Zero, 0, bytesReturned) End Function

星期二, 9月 09, 2008

.NET強大簡單的多執行緒功能

多執行緒(MultiThread)是系統效能的強力工具,可以將原本低效率的程式以分工的方式提升數倍,對於核心開發的工作,如WinCE,多執行緒變成不可不熟悉的技術,例如處理IO,當大量資料進入系統的時候,總不能讓User看到系統發呆的難看景象吧~那誰要買我們的系統呢?

還好,微軟強大的軟體工程師幫你簡化的這方面的問題,對於多執行緒的開發,兩行指令就能處置,當然,除了「開線」外,其他還有很多必須知道的事,例如非同步執行緒的資料同步問題、各執行緒與UI之間的溝通等等,在此先稍微開場,如何開多線。

標準的執行緒開啟:

Dim mythread As New System.Threading.Thread(AddressOf myProccess)

mythread.Start()

Private Sub myProccess()

.....

End Sub

指令相當簡單,開啟一個新的執行緒去執行myProccess()副程式,當然你可以用mythread.Name為這個執行緒命名,其中執行緒也含有一些方法,如Abort,但在經驗來講WinCE中似乎並非每次都管用,所以我的建議myProccess副程式最好內寫好退出執行緒的路子,免的出現關閉程式還是沒辦法結束副執行緒的窘境。

第二個方法執行緒集區(ThreadPool),是用隨時會有大量執行緒需求,而每個執行緒執行時間短且都會釋放時,會選擇使用ThreadPool,以前想達程ThreadPool的要考慮的問題很多,NET已經簡化這些問題了,事實上當開啟一NET程式,CLR已經提供我們一顆CPU 25條的ThreadPool使用,其使用方式也很簡單:

Dim myCallback As New System.Threading.WaitCallback(AddressOf myProccess)

System.Threading.ThreadPool.QueueUserWorkItem( myCallback , Sendata)

Private Sub myProccess(Byval state as Object)

.....

End Sub

其中WaitCallback是執行緒集區執行緒執行的回呼方法,若要建立委派,您可以將回呼方法傳遞至 WaitCallback 建構函式,比較需要注意的是其副程式要含有傳入參數state,這是必要格式。之後只要使用ThreadPool.QueueUserWorkItem即可交給CLR管理我們的ThreadPool,程式非常簡潔就能提升效能,M$真的是太貼心了。

星期日, 9月 07, 2008

P/Invoke與簡單型別說明

呼叫未受限制程式碼是.NET開發WinCE相當常遇到,原因無他,幾乎所有WinCE硬體開發出的Driver或DLL都是用未受限制的Win32API提供服務,現改寫成.NET DLL的非常少,一方面未受限制的程式效能確實遠遠超過.NET,另一方面敝人認為.NET跳脫原本執行環境Sandbox界線而呼叫未受限公用程式的能力相當強,兩種原因下,系統開法者並不需要特別專為.NET開發DLL。

定義範例如下:

[DllImport ("coredll.dll")]
Private static extern void SetWindowText(IntPtr handle, string s);

以上不詳述dllimport的語法,基本上如此設定便夠應付大部分未受限API。

在使用P/Invoke執行WinCE或Win32API卻發現結果不正確,經常都是函數引數的型別定義不正確,下表為其定義轉換參考:


win32 types specification clr type
char, int8, sbyte 8-bit signed integer system.sbyte
short, short int, int16, short 16-bit signed integer system.int16
int, long, long int, int32, long32, int 32-bit signed integer system.int32
__int64, int64, longlong 64-bit signed integer system.int64
unsigned char, uint8, byte 8-bit unsigned integer system.byte
unsigned short, uint16, ushort, word, atom, __wchar_t 16-bit unsigned integer system.uint16
unsigned, unsigned int, uint32, ulong32, dword32, ulong, dword, uint 32-bit unsigned integer system.uint32
unsigned __int64, uint64, dwordlong, ulonglong 64-bit unsigned integer system.uint64
float, float single-precision floating point system.single
double, long double, double double-precision floating point system.double

最重要的是引述位元數必須相同對應,函數才能正常傳值。

星期四, 9月 04, 2008

又突然暴跌一千點

這幾天挺忙的所以沒注意股票,朋友提點最近空頭走勢,賣掉一半股票,但沒想到會突然摔到六千二,瞬間從小賺便成大賠,早知道就多賣掉一點 >_< 。算了,這時候就想到司令的一席話:

投資最大敵人就是自己,切記

1.多轉折做多
2.空轉折出場
3.空頭不要期待太多
4.空頭只能小玩
5.七千五以上不操作小型股(低檔買上上去除外)
6.暴跌只能操作大型股
7.長空一年以上改做小型股
8.不意識型態操作
9.不攤平
10.不抱持僥倖
11.不賭
12.不借錢投資
13.不投資不懂的東西

VB.NET簡單存取Byte變數中各Bit

Sub WriteBit(ByRef Data As byte,ByVal BitIndex As Integer, ByVal NewBit As Boolean)

If NewBit = True Then
Data = Data And Math.Pow(2, BitIndex)
Else
Data = Data And (&HFF - Math.Pow(2, BitIndex))
End If

End Sub


Function ReadBit(ByRef Data As byte,ByVal BitIndex As Integer) as Boolean

return (Data And Math.Pow(2, BitIndex))) / Math.Pow(2, BitIndex)

End Sub

星期三, 9月 03, 2008

組合語言站存器介紹

1.通用暫存器

共有四個,其名稱分別是 AX、BX、CX、DX,在組合語言程式中大致沒有太大的差別,但是其中只有 AX ( accumulator,也稱為累加器) 可作為除法或乘法中的被除數與被乘數,當 16 位元不夠大時,常常用 DX:AX 來表示 32 位元。此外這四個暫存器,只有 BX ( base register,也稱為基底暫存器) 可以被作為位址存取之用。CX 也稱為計數暫存器 ( count register),用於計算迴圈之次數或字串處理之次數。DX 也稱為資料暫存器 ( data register),可用來存取埠。

這四個暫存器也可以分成兩個 8 位元的暫存器來使用,例如 AX 可被分成較低的 8 位元稱為 AL,以及較高的 8 位元 AH 來使用。其餘 BX、CX、DX 也都類似。

2.指標與索引暫存器

有五個,其名稱分別是 SP、BP、IP、SI、DI。前面兩個 SP (stack pointer,稱為堆疊指標)與(base pointer,也稱為基底指標)是與堆疊(stack)有關的暫存器,以獲得詳細的堆疊資料。堆疊是一塊區域,用來暫時存放資料之用,在 8086/8088 中,堆疊是由最高位址中開始存放,每次都必須存入一個字組的長度,並用一組指標,來表示堆疊已經使用到那兒了,這組指標就是 SS:SP。也就是說,當成是要將資料存入堆疊時,該資料應該存放在 SS:SP 所指的位址再低 2 個位元組,然後 CPU 再使 SP 之內容減 2,使 SP 再指到下一個未使用的空間。

那什麼情形會要將資料存入堆疊內呢?有好幾種情形,例如呼叫副程式時,會預先把返回位址存入堆疊﹔呼叫中斷時也是如此。BP 通常用於呼叫副程式時,傳遞參數之用。

IP (instruction pointer,稱為指令指標) 配合 CS 變成 CS:IP,指向將要執行的 8086/8088 位址。當 CPU 要執行程式時,必須到記憶體去提取要執行的指令,而要到那一個記憶體位址去提取指令呢?這時 CPU 就會到 CS:IP 指到的位址去提取。在程式中,一般是沒有辦法改變 CS:IP 的值,除非是跳躍 (jmp、jz等) 指令或是呼叫 (call、ret等) 指令。

SI (source index,稱為來源索引暫存器) 和 DI (destination index,稱為目的索引暫存器) 通常是用來當作位址指標,也可用作加減法。這五個暫存器,每一個都不能分開來當作兩個 8 位元的暫存器使用。

3.區段暫存器

有 CS、DS、ES、SS 四個,分別表示程式碼(code segment register)、資料(data segment register)、額外(extra segment register)、堆疊(stack segment register)區段之用。在 DOS 系統中,每一個區段容量只有 64KBytes。

當資料區段不夠用時,就可以用額外區段來補足,例如想要將一個區段的某些內容複製到另一區段中,就可以同時指定 DS、ES 分別表示這兩個區段。

4.旗標暫存器

旗標暫存器 (flag register) 是一個 16 位元的暫存器,但只有其中九個位元有用到,它們分散在這十六個位元中,採用這種分散方式是為了與舊式的 8080 CPU 的旗標相同。這 9 個旗標可分為三類:狀態旗標 ( status flag )、控制旗標 ( control flag ) 與系統旗標 ( system flag )。狀態旗標包含 CF、PF、AF、ZF、SF 和 OF,它們會受到算術、比較或邏輯運算結果狀態的影響,而使旗標被設定 ( set,其值為 1 ),或被清除 ( clear,其值為零 )。第 10 位元的 DF 用來控制掃描、搬移、搜尋字串的方向,屬於控制旗標。至於 IF、TF 為設計作業系統、除錯時才需要用到,屬於系統旗標,一般應用程式很少使用。底下簡單介紹這些旗標:

名稱

位元

狀態

說明

進位旗標
carry flag
CF

0 CF=1,CY
CF=0,NC

當運算發生進位或借位時,ZF 被設為 1;反之設為 0。例如兩數相加:

        mov     ax,8000h
        add     ax,8000h

8000h+8000h 應為 10000h,發生進位,雖然 AX 為 0,但是會使 CF 設為一,表示進位。

同位旗標
parity flag
PF

2 PF=1,PE
PF=0,PO
運算的結果換成二進位後,最低的 8 個位元中,若有偶數個 1,則此位元設為 1,反之為 0。

輔助進位旗標
auxiliary carry flag
AF

4 AF=1,AC
AF=0,NA
當運算過程中,第 3 位元與第 4 位元之間發生進位或借位時,AF 被設為 1,否則被設為 0,常用於 BCD 的運算。

零旗標
zero flag
ZF

6 ZF=1,ZR
ZF=0,NZ
運算結果為零時,ZF 會被設定為 1。若比較相同兩數, ZF 也會被設為一,若比較不相同的兩數,ZF 會被清除為零。例如:
        mov     ax,8000h
        add     ax,8000h

相加後,AX 為零,故 ZF 設為一。

符號旗標
sign flag
SF

7 SF=1,NG
SF=0,PL
運算結果的最高位元為 1 時,SF 會被設為 1 ( 表示負數 ),否則被清除。

陷阱旗標
trap flag
TF

8   用於單步追蹤除錯時,所以也稱為追蹤旗標 ( trace flag ),例如在 MS-DOS 的 DEBUG 中,就是利用 TF 達到單步追蹤的目的。當 TF 設為一時,每執行一個指令便會發生中斷,此中斷就將執行該指令後暫存器列出。

中斷旗標
interrupt flag
IF

9 IF=1,EI
IF=0,DI
當 IF 被設定時,可遮罩的硬體中斷才能使 CPU 產生中斷效果;反之所有可遮罩的硬體中斷均會被抑制。但是不可遮罩中斷以及 CPU 產生的例外卻完全不受 IF 影響。

方向旗標
direction flag
DF

10 DF=1,DN
DF=0,UP
當 DF 被清除時 ( 即 DF=0 ),處理字串的索引暫存器會遞增,往高位址方向處理,反之則遞減。

溢位旗標
overflow flag
OF

11 OF=1,OV
OF=0,NV

當運算結果無法容納於目的運算元中,此旗標會被設為一。大致可分三種情形:(1)兩同號數相加或兩異號數相減,(2)乘除運算時,所得的積或商超過運算元存放範圍,在移位或旋轉指令時,最高位元值受到更動 ( 0 變成 1 或 1 變成 0 )。

在此列出 DEBUG 中執行 r 指令後的意義:

-r [Enter]
AX=0000  BX=0000  CX=0025  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=10F7  ES=10F7  SS=10F7  CS=10F7  IP=0100   NV UP EI PL NZ NA PO NC
10F7:0100 EB19           JMP    0119

英文字母NV UP EI PL等等就是旗標的狀態,請看下表:

旗標名稱 設定(1) 清除(0)
CF,進位(是/否)
PF,同位(偶數/基數)
AF,輔助進位(是/否)
ZF,零(是/否)
SF,符號(是/否)
IF,中斷(允許/抑制)
DF,方向(遞減/遞增)
OF,溢位(是/否)
CY
PE
AC
ZR
NG
EI
DN
OV
NC
PO
NA
NZ
PL
DI
UP
NV

組合語言基本指令

一,數據傳送指令集
1.MOV

功能: 把源操作數送給目的操作數
語法: MOV 目的操作數,源操作數
格式: MOV r1,r2
MOV r,m
MOV m,r
MOV r,data

2.XCHG

功能: 交換兩個操作數的數據
語法: XCHG
格式: XCHG r1,r2 XCHG m,r XCHG r,m


3.PUSH,POP

功能: 把操作數壓入或取出堆棧
語法: PUSH 操作數 POP 操作數
格式: PUSH r PUSH M PUSH data POP r POP m


4.PUSHF,POPF,PUSHA,POPA

功能: 堆棧指令群
格式: PUSHF POPF PUSHA POPA

5.LEA,LDS,LES

功能: 取地址至寄存器
語法: LEA r,m LDS r,m LES r,m


6.XLAT(XLATB)

功能: 查表指令
語法: XLAT XLAT m

二,算數運算指令
1..ADD,ADC

功能: 加法指令
語法: ADD OP1,OP2 ADC OP1,OP2
格式: ADD r1,r2 ADD r,m ADD m,r ADD r,data
影響標志: C,P,A,Z,S,O

2..S U B,SBB

功能:減法指令
語法: S U B OP1,OP2 SBB OP1,OP2
格式: S U B r1,r2 S U B r,m S U B m,r S U B r,data S U B m,data
影響標志: C,P,A,Z,S,O

3.INC,DEC

功能: 把OP的值加一或減一
語法: INC OP DEC OP
格式: INC r/m DEC r/m
影響標志: P,A,Z,S,O


4.NEG

功能: 將OP的符號反相(取二進制補碼)
語法: NEG OP
格式: NEG r/m
影響標志: C,P,A,Z,S,O


5.MUL,IMUL

功能: 乘法指令
語法: MUL OP IMUL OP
格式: MUL r/m IMUL r/m
影響標志: C,P,A,Z,S,O(僅IMUL會影響S標志)


6.DIV,IDIV

功能:除法指令
語法: DIV OP IDIV OP
格式: DIV r/m IDIV r/m


7.CBW,CWD

功能: 有符號數擴展指令
語法: CBW CWD


8.AAA,AAS,AAM,AAD

功能: 非壓BCD碼運算調整指令
語法: AAA AAS AAM AAD
影響標志: A,C(AAA,AAS) S,Z,P(AAM,AAD)


9.DAA,DAS

功能: 壓縮BCD碼調整指令
語法: DAA DAS
影響標志: C,P,A,Z,S

三,位運算指令集
1.AND,OR,XOR,NOT,TEST

功能: 執行BIT與BIT之間的邏輯運算
語法: AND r/m,r/m/data OR r/m,r/m/data XOR r/m,r/m/data TEST r/m,r/m/d
ata NOT r/m
影響標志: C,O,P,Z,S(其中C與O兩個標志會被設為0) NOT指令不影響任何標志位


2.SHR,SHL,SAR,SAL

功能: 移位指令
語法: SHR r/m,data/CL SHL r/m,data/CL SAR r/m,data/CL SAL r/m,data/CL
影響標志: C,P,Z,S,O


3.ROR,ROL,RCR,RCL

功能: 循環移位指令
語法: ROR r/m,data/CL ROL r/m,data/CL RCR r/m,data/CL RCL r/m,data/CL
影響標志: C,P,Z,S,O

四,程序流程控制指令集
1.CLC,STC,CMC

功能: 設定進位標志
語法: CLC STC CMC
標志位: C

2.CLD,STD

功能: 設定方向標志
語法: CLD STD
標志位: D


3.CLI,STI

功能: 設定中斷標志
語法: CLI STI
標志位: I


4.CMP

功能: 比較OP1與OP2的值
語法: CMP r/m,r/m/data
標志位: C,P,A,Z,O


5.JMP

功能: 跳往指定地址執行
語法: JMP 地址


6.JXX

功能: 當特定條件成立則跳往指定地址執行
語法: JXX 地址
注:
A: ABOVE,當C=0,Z=0時成立
B: BELOW,當C=1時成立
C: CARRY,當弁時成立 CXZ: CX寄存器的值為0(ZERO)時成立
E: EQUAL,當Z=1時成立
G: GREATER(大於),當Z=0且S=0時成立
L: LESS(小於),當S不為零時成立
N: NOT(相反條件),需和其它符號配合使用
O: OVERFLOW,O=1時成立
P: PARITY,P=1時成立
PE: PARITY EVEN,P=1時成立
PO: PARITY ODD,P=0時成立
S: SIGN,S=1時成立
Z: ZERO,Z=1時成立

7.LOOP

功能: 循環指令集
語法: LOOP 地址


8.LOOPE(Z)

地址 LOOPNE(Z) 地址
標志位: 無


9.CALL,RET

功能: 子程序調用,返回指令
語法: CALL 地址 RET RET n
標志位: 無


10.INT,IRET

功能: 中斷調用及返回指令
語法: INT n IRET
標志位: 在執行INT時,CPU會自動將標志寄存器的值入棧,在執行IRET時則會將堆
棧中的標志值彈回寄存器

五,字符串操作指令集
1.MOVSB,MOVSW,MOVSD

功能: 字符串傳送指令
語法: MOVSB MOVSW MOVSD
標志位: 無


2.CMPSB,CMPSW,CMPSD

功能: 字符串比較指令
語法: CMPSB CMPSW CMPSD
標志位: C,P,Z,S,O


3.SCASB,SCASW

功能: 字符串搜索指令
語法: SCASB SCASW
標志位: C,P,Z,S,O


4.LODSB,LODSW,STOSB,STOSW

功能: 字符串載入或存貯指令
語法: LODSB LODSW STOSB STOSW
標志位: 無


5.REP,REPE,REPNE

功能: 重復前綴指令集
語法: REP 指令S REPE 指令S REPNE 指令S
標志位: 依指令S而定

星期三, 8月 27, 2008

組語基礎篇-Lea與Mov

這兩天為了替同事上課,整理一些基礎的組合語言資料,本來想說用google大神剪剪貼貼就搞定,但發現一件十分有趣的事,就是這lea與mov兩個指令,似乎都說是「近似」的指令,讓人非常傻眼,還很少人更正,是這種低級語言....不不低階語言已經乏人問津了還是忽視,反正我也在整理資料,順便寫一下,這兩個天壤之別的指令到底差在哪裡。

  • Lea傳遞變數位置
  • Mov傳遞變數數值

學過C++的,應該很容易了解吧~~就是指指標的 *X1 語 &X1。我也很納悶為什麼那麼多人會說兩者差不多,我想,可能為誤會的原因應該是組語「字串」傳遞所害的,舉例來講:

lpCaption="Caption"
lpText="Hello World!"

_asm
{
push MB_OK
lea eax,lpCaption
push eax
lea eax,lpText
push eax
push NULL
call dword ptr [MessageBoxA]
}

假定我有兩個字串lpCaption與lpText,要傳遞給MessageBoxA來彈出一個視窗,我必須將MessageBoxA所需的三個變數MB_OK、lpCaption、lpText三個參數依序push入堆疊再call MessageBoxA,此時再傳遞lpCation會用到 lea eax,lpText,不懂原由的人就會以為mov和lea是差距不大,但事實上換用mov一定是出現亂碼,因為傳遞字串與陣列是必須傳遞字串或陣列的起始位置。

星期二, 8月 26, 2008

強大的反組譯軟體 PE Explorer

系統開發最長遇到的、也是最賭濫的事,就是明明很簡單的程式,卻怎麼執行IO就是一動也不動,怎麼看都可能是與Driver連動出問題卻無處著手,唯一除此bug方法就是將編譯好的程式碼反組譯,直接看裡面在搞些什麼。
PE Explorer 是我目前用過最為強大的反組譯的軟體,可以分析EXE執行檔、DLL程式庫以及ActiveX等元件,可以分析其資源以及程式中使用的外部函數,十分方便。

執行畫面如下: