pid匯編程序
『壹』 哪位高手可以給一份用匯編語言編寫的增量型PID演算法的程序,謝謝
;********增量式PID控制演算法程序*********** 
;T、TD、TI、KP依次從30H,33H,36H,39H開始。 
;A,B,C的值依次存在BLOCK1,BLOCK2,BLOCK3的地址里 
; 這里R(k)給的是定值 
ORG 0000H 
BLOCK1 EQU 43H ;A,B ,C 
BLOCK2 EQU 46H 
BLOCK3 EQU 49H 
UK EQU 4CH ;存結果UK 
RK EQU 50H 
EK EQU 53H ;存放偏差值E(k)的始址 
EK1 EQU 56H ;存放E(k-1)的始址 
EK2 EQU 59H ;存放E(k-2)的始址 
CK EQU 5CH ;采樣數據始址 
BUFF EQU 60H ;暫存區 
BUFF1 EQU 63H 
BUFF2 EQU 66H 
REC EQU 69H 
TEST: 
MOV RK,#01H ;常數Rk的BCD碼浮點數 
MOV RK+1,#12H ;1.25 
MOV RK+2,#50H 
MOV 3CH,#01H ;常數1的BCD碼浮點數 
MOV 3DH,#10H 
MOV 3EH,#00H 
MOV 40H,#01H ;常數2的BCD碼浮點數 
MOV 41H,#20H 
MOV 42H,#00H 
MOV 30H,#01H ;T的BCD 碼浮點數 
MOV 31H,#23H ;2.34 
MOV 32H,#40H 
MOV 33H,#01H ;Td的BCD碼浮點數 
MOV 34H,#35H ;3.54 
MOV 35H,#40H 
MOV 36H,#01H ;Ti的BCD碼浮點數 
MOV 37H,#11H ;1.12 
MOV 38H,#20H 
MOV 39H,#01H ;Kp的BCD碼浮點數 
MOV 3AH,#12H ;1.25 
MOV 3BH,#50H 
MOV R0,#RK ;指向BCD碼浮點操作數 
LCALL BTOF ;將其轉換成二進制浮點操作數 
MOV R0,#3CH 
LCALL BTOF 
MOV R0,#40H 
LCALL BTOF 
MOV R0,#39H 
LCALL BTOF 
MOV R0,#36H ;指向BCD碼浮點操作數Ti 
LCALL BTOF ;將其轉換成二進制浮點操作數 
MOV R0,#33H ;指向BCD碼浮點操作數Td 
LCALL BTOF ;將其轉換成二進制浮點操作數 
MOV R0,#30H ;指向BCD碼浮點操作數T 
LCALL BTOF ;將其轉換成二進制浮點操作數 
MOV R1, #BUFF1 ;保存30H中的值 即T值 
LCALL FMOVR0 
MOV R1, #36H ;計算A值(1+T/Ti+Td/T).Kp 
LCALL FDIV 
MOV R1,#3CH ;常數1 
LCALL FADD 
MOV R0,#33H ;保存33H中的值 
MOV R1,#BUFF 
LCALL FMOVR0 
MOV R1,#BUFF1 
LCALL FDIV 
MOV R1,#30H ;30H里存的是T/Ti+1 
LCALL FADD 
MOV R1,#39H 
LCALL FMUL 
MOV R1 ,#BLOCK1 ;將結果保存在BLOCK1中 
LCALL FMOVR0 
MOV R1,#BUFF1 ;30H恢復原值 
MOV R0,#30H 
LCALL FMOV 
MOV R1,#BUFF ;33H恢復原值 
MOV R0,#33H 
LCALL FMOV 
MOV R0,#40H ;計算B的值Kp.(1+2.Td/T) 
MOV R1,#33H 
LCALL FMUL 
MOV R1,#30H 
LCALL FDIV 
MOV R1,#3CH 
LCALL FADD 
MOV R1,#39H 
LCALL FMUL 
MOV R1,#BLOCK2 ;保存B值到BLOCK2中 
LCALL FMOVR0 
MOV R0,#39H ;計算C的值Kp.Td/T 
MOV R1,#33H 
LCALL FMUL 
MOV R1,#30H 
LCALL FDIV 
MOV R1,#BLOCK3 ;保存C值到BLOCK3中 
LCALL FMOVR0 
MOV R0,#EK1 ;將EK1,EK2設初值0 
LCALL FCLR 
MOV R0,#EK2 
LCALL FCLR 
MOV REC,#03H ;設置采樣次數 
LOOP: MOV CK,#7eH ;采樣數據暫時給了一個定值 
MOV CK+1,#21H ;0.002112 
MOV CK+2,#12H 
MOV R0,#CK 
LCALL BTOF 
MOV R0,#RK ;保存R(k)中的值 
MOV R1,#BUFF 
LCALL FMOVR0 
MOV R1,#CK 
LCALL FSUB ;計算R(k)-C(k)的值送給E(k) 
MOV R1,#EK 
LCALL FMOVR0 
MOV R1,#BUFF ;恢復RK的值 釋放BUFF 
MOV R0,#RK 
LCALL FMOV 
MOV R0,#BLOCK2 ;將B.e(k-1)的值暫存在BUFF1中 
MOV R1,#BUFF ;保存B 
LCALL FMOVR0 
MOV R1,#EK1 
LCALL FMUL 
MOV R1,#BUFF1 
LCALL FMOVR0 
MOV R1,#BUFF ;恢復B釋放BUFF 
LCALL FMOV 
MOV R0,#BLOCK3 ;將C.e(K-2)的值暫存在BUFF2中 
MOV R1,#BUFF ;保存C 
LCALL FMOVR0 
MOV R1,#EK2 
LCALL FMUL 
MOV R1,#BUFF2 
LCALL FMOVR0 
MOV R1,#BUFF ;恢復C釋放BUFF 
LCALL FMOV 
MOV R0,#BLOCK1 ;A.E(k) 
MOV R1,#BUFF 
LCALL FMOVR0 
MOV R1,#EK 
LCALL FMUL 
MOV R1,#BUFF1 ;計算Uk值A.E(k)-B.E(k-1)+C.E(k-2) 
LCALL FSUB 
MOV R1,#BUFF2 
LCALL FADD 
MOV R1,#UK ;保存結果到UK中 
LCALL FMOVR0 
MOV R1,#BUFF ;恢復A 釋放BUFF 
LCALL FMOV 
MOV R0,#UK ;UK轉換成BCD碼浮點數輸出 
LCALL FTOB 
MOV R1,#EK1 ;將E(k-1)-->E(k-2),E(k)-->E(k-1) 
MOV R0,#EK2 
LCALL FMOV 
MOV R1,#EK 
MOV R0,#EK1 
LCALL FMOV 
LCALL DELAY ;等待采樣時刻 
DJNZ REC,NEXT1 
SJMP $ 
NEXT1: LJMP LOOP 
DELAY: MOV R7,#02H 
DELAY1: MOV R6,#0FFH 
DELAY2: DJNZ R6,DELAY2 
DJNZ R7,DELAY1 
RET 
; (1) 標號: FSDT 功能:浮點數格式化 
;入口條件:待格式化浮點操作數在[R0]中。 
;出口信息:已格式化浮點操作數仍在[R0]中。 
;影響資源:PSW、A、R2、R3、R4、位1FH 堆棧需求: 6位元組 
FSDT: LCALL MVR0 ;將待格式化操作數傳送到第一工作區中 
LCALL RLN ;通過左規完成格式化 
LJMP MOV0 ;將已格式化浮點操作數傳回到[R0]中 
; (2) 標號: FADD 功能:浮點數加法 
;入口條件:被加數在[R0]中,加數在[R1]中。 
;出口信息:OV=0時,和仍在[R0]中,OV=1時,溢出。 
;;影響資源:PSW、A、B、R2~R7、位1EH、1FH 堆棧需求: 6位元組 
FADD: CLR F0 ;設立加法標志 
SJMP AS ;計算代數和 
; (3) 標號: FSUB 功能:浮點數減法 
;入口條件:被減數在[R0]中,減數在[R1]中。 
;出口信息:OV=0時,差仍在[R0]中,OV=1時,溢出。 
;影響資源:PSW、A、B、R2~R7、位1EH、1FH 堆棧需求:6位元組 
FSUB: SETB F0 ;設立減法標志 
AS: LCALL MVR1 ;計算代數和。先將[R1]傳送到第二工作區 
MOV C,F0 ;用加減標志來校正第二操作數的有效符號 
CLR A ; ********???應加的一條語句 
RRC A 
XRL A,@R1 
MOV C,ACC.7 
ASN: MOV 1EH,C ;將第二操作數的有效符號存入位1EH中 
XRL A,@R0 ;與第一操作數的符號比較 
RLC A 
MOV F0,C ;保存比較結果 
LCALL MVR0 ;將[R0]傳送到第一工作區中 
LCALL AS1 ;在工作寄存器中完成代數運算 
MOV0: INC R0 ;將結果傳回到[R0]中的子程序入口 
INC R0 
MOV A,R4 ;傳回尾數的低位元組 
MOV @R0,A 
DEC R0 
MOV A,R3 ;傳回尾數的高位元組 
MOV @R0,A 
DEC R0 
MOV A,R2 ;取結果的階碼 
MOV C,1FH ;取結果的數符 
MOV ACC.7,C ;拼入階碼中 
MOV @R0,A 
CLR ACC.7 ;不考慮數符 
CLR OV ;清除溢出標志 
CJNE A,#3FH,MV01;階碼是否上溢? ******** 應為#40H 
SETB OV ;設立溢出標志 
MV01: MOV A,@R0 ;取出帶數符的階碼 
RET 
MVR0: MOV A,@R0 ;將[R0]傳送到第一工作區中的子程序 
MOV C,ACC.7 ;將數符保存在位1FH中 
MOV 1FH,C 
MOV C,ACC.6 ;將階碼擴充為8bit補碼 
MOV ACC.7,C 
MOV R2,A ;存放在R2中 
INC R0 
MOV A,@R0 ;將尾數高位元組存放在R3中 
MOV R3,A ; 
INC R0 
MOV A,@R0 ;將尾數低位元組存放在R4中 
MOV R4,A 
DEC R0 ;恢復數據指針 
DEC R0 
RET 
MVR1: MOV A,@R1 ;將[R1]傳送到第二工作區中的子程序 
MOV C,ACC.7 ;將數符保存在位1EH中 
MOV 1EH,C 
MOV C,ACC.6 ;將階碼擴充為8bit補碼 
MOV ACC.7,C 
MOV R5,A ;存放在R5中 
INC R1 
MOV A,@R1 ;將尾數高位元組存放在R6中 
MOV R6,A 
INC R1 
MOV A,@R1 ;將尾數低位元組存放在R7中 
MOV R7,A 
DEC R1 ;恢復數據指針 
DEC R1 
RET 
AS1: MOV A,R6 ;讀取第二操作數尾數高位元組 
ORL A,R7 
JZ AS2 ;第二操作數為零,不必運算 
MOV A,R3 ;讀取第一操作數尾數高位元組 
ORL A,R4 
JNZ EQ 
MOV A,R6 ;第一操作數為零,結果以第二操作數為准 
MOV R3,A 
MOV A,R7 
MOV R4,A 
MOV A,R5 
MOV R2,A 
MOV C,1EH 
MOV 1FH,C 
AS2: RET 
EQ: MOV A,R2 ;對階,比較兩個操作數的階碼 
XRL A,R5 
JZ AS4 ;階碼相同,對階結束 
JB ACC.7,EQ3;階符互異 
MOV A,R2 ;階符相同,比較大小 
CLR C 
SUBB A,R5 
JC EQ4 
EQ2: CLR C ;第二操作數右規一次 
MOV A,R6 ;尾數縮小一半 
RRC A 
MOV R6,A 
MOV A,R7 
RRC A 
MOV R7,A 
INC R5 ;階碼加一 
ORL A,R6 ;尾數為零否? 
JNZ EQ ;尾數不為零,繼續對階 
MOV A,R2 ;尾數為零,提前結束對階 
MOV R5,A 
SJMP AS4 
EQ3: MOV A,R2 ;判斷第一操作數階符 
JNB ACC.7,EQ2;如為正,右規第二操作數 
EQ4: CLR C 
LCALL RR1 ;第一操作數右規一次 
ORL A,R3 ;尾數為零否? 
JNZ EQ ;不為零,繼續對階 
MOV A,R5 ;尾數為零,提前結束對階 
MOV R2,A 
AS4: JB F0,AS5 ;尾數加減判斷 
MOV A,R4 ;尾數相加 
ADD A,R7 
MOV R4,A 
MOV A,R3 
ADDC A,R6 
MOV R3,A 
JNC AS2 
LJMP RR1 ;有進位,右規一次 
AS5: CLR C ;比較絕對值大小 
MOV A,R4 
SUBB A,R7 
MOV B,A 
MOV A,R3 
SUBB A,R6 
JC AS6 
MOV R4,B ;第一尾數減第二尾數 
MOV R3,A 
LJMP RLN ;結果規格化 
AS6: CPL 1FH ;結果的符號與第一操作數相反 
CLR C ;結果的絕對值為第二尾數減第一尾數 
MOV A,R7 
SUBB A,R4 
MOV R4,A 
MOV A,R6 
SUBB A,R3 
MOV R3,A 
RLN: MOV A,R3 ;浮點數規格化 
ORL A,R4 ;尾數為零否? 
JNZ RLN1 
MOV R2,#0C1H;階碼取最小值 ******??應為#C0H 
RET 
RLN1: MOV A,R3 
JB ACC.7,RLN2;尾數最高位為一否? 
CLR C ;不為一,左規一次 
LCALL RL1 
SJMP RLN ;繼續判斷 
RLN2: CLR OV ;規格化結束 
RET 
RL1: MOV A,R4 ;第一操作數左規一次 
RLC A ;尾數擴大一倍 
MOV R4,A 
MOV A,R3 
RLC A 
MOV R3,A 
DEC R2 ;階碼減一 
CJNE R2,#0C0H,RL1E;階碼下溢否? ***** 應改為CJNE R2,#0BFH,RL1E; 
CLR A 
MOV R3,A ;階碼下溢,操作數以零計 
MOV R4,A 
MOV R2,#0C1H ; ******應改為MOV R2,#0C0H 
RL1E: CLR OV 
RET 
RR1: MOV A,R3 ;第一操作數右規一次 
RRC A ;尾數縮小一半 
MOV R3,A 
MOV A,R4 
RRC A 
MOV R4,A 
INC R2 ;階碼加一 
CLR OV ;清溢出標志 
CJNE R2,#40H,RR1E;階碼上溢否? 
MOV R2,#3FH ;階碼溢出 
SETB OV 
RR1E: RET 
; (4) 標號: FMUL 功能:浮點數乘法 
;入口條件:被乘數在[R0]中,乘數在[R1]中。 
;出口信息:OV=0時,積仍在[R0]中,OV=1時,溢出。 
;影響資源:PSW、A、B、R2~R7、位1EH、1FH 堆棧需求:6位元組 
FMUL: LCALL MVR0 ;將[R0]傳送到第一工作區中 
MOV A,@R0 
XRL A,@R1 ;比較兩個操作數的符號 
RLC A 
MOV 1FH,C ;保存積的符號 
LCALL MUL0 ;計算積的絕對值 
LJMP MOV0 ;將結果傳回到[R0]中 
MUL0: LCALL MVR1 ;將[R1]傳送到第二工作區中 
MUL1: MOV A,R3 ;第一尾數為零否? 
ORL A,R4 
JZ MUL6 
MOV A,R6 ;第二尾數為零否? 
ORL A,R7 
JZ MUL5 
MOV A,R7 ;計算R3R4×R6R7-→R3R4 
MOV B,R4 
MUL AB 
MOV A,B 
XCH A,R7 
MOV B,R3 
MUL AB 
ADD A,R7 
MOV R7,A 
CLR A 
ADDC A,B 
XCH A,R4 
MOV B,R6 
MUL AB 
ADD A,R7 
MOV R7,A 
MOV A,B 
ADDC A,R4 
MOV R4,A 
CLR A 
RLC A 
XCH A,R3 
MOV B,R6 
MUL AB 
ADD A,R4 
MOV R4,A 
MOV A,B 
ADDC A,R3 
MOV R3,A 
JB ACC.7,MUL2;積為規格化數否? R7四捨五入 
MOV A,R7 ;左規一次 
RLC A 
MOV R7,A 
LCALL RL1 
MUL2: MOV A,R7 
JNB ACC.7,MUL3 
INC R4 
MOV A,R4 
JNZ MUL3 
INC R3 
MOV A,R3 
JNZ MUL3 
MOV R3,#80H 
INC R2 
MUL3: MOV A,R2 ;求積的階碼 
ADD A,R5 
MD: MOV R2,A ;階碼溢出判斷 
JB ACC.7,MUL4 
JNB ACC.6,MUL6 
MOV R2,#3FH ;階碼上溢,設立標志 
SETB OV 
RET 
MUL4: JB ACC.6,MUL6 
MUL5: CLR A ;結果清零(因子為零或階碼下溢) 
MOV R3,A 
MOV R4,A 
MOV R2,#41H 
MUL6: CLR OV 
RET 
; (5) 標號: FDIV 功能:浮點數除法 
;入口條件:被除數在[R0]中,除數在[R1]中。 
;出口信息:OV=0時,商仍在[R0]中,OV=1時,溢出。 
;影響資源:PSW、A、B、R2~R7、位1EH、1FH 堆棧需求: 5位元組 
FDIV: INC R0 
MOV A,@R0 
INC R0 
ORL A,@R0 
DEC R0 
DEC R0 
JNZ DIV1 
MOV @R0,#41H;被除數為零,不必運算 
CLR OV 
RET 
DIV1: INC R1 
MOV A,@R1 
INC R1 
ORL A,@R1 
DEC R1 
DEC R1 
JNZ DIV2 
SETB OV ;除數為零,溢出 
RET 
DIV2: LCALL MVR0 ;將[R0]傳送到第一工作區中 
MOV A,@R0 
XRL A,@R1 ;比較兩個操作數的符號 
RLC A 
MOV 1FH,C ;保存結果的符號 
LCALL MVR1 ;將[R1]傳送到第二工作區中 
LCALL DIV3 ;調用工作區浮點除法 
LJMP MOV0 ;回傳結果 
DIV3: CLR C ;比較尾數的大小 
MOV A,R4 
SUBB A,R7 
MOV A,R3 
SUBB A,R6 
JC DIV4 
LCALL RR1 ;被除數右規一次 
SJMP DIV3 
DIV4: CLR A ;借用R0R1R2作工作寄存器 
XCH A,R0 ;清零並保護之 
PUSH ACC 
CLR A 
XCH A,R1 
PUSH ACC 
MOV A,R2 
PUSH ACC 
MOV B,#10H ;除法運算,R3R4/R6R7-→R0R1 
DIV5: CLR C 
MOV A,R1 
RLC A 
MOV R1,A 
MOV A,R0 
RLC A 
MOV R0,A 
MOV A,R4 
RLC A 
MOV R4,A 
XCH A,R3 
RLC A 
XCH A,R3 
MOV F0,C 
CLR C 
SUBB A,R7 
MOV R2,A 
MOV A,R3 
SUBB A,R6 
ANL C,/F0 
JC DIV6 
MOV R3,A 
MOV A,R2 
MOV R4,A 
INC R1 
DIV6: DJNZ B,DIV5 
MOV A,R6 ;四捨五入 
CLR C 
RRC A 
SUBB A,R3 
CLR A 
ADDC A,R1 ;將結果存回R3R4 
MOV R4,A 
CLR A 
ADDC A,R0 
MOV R3,A 
POP ACC ;恢復R0R1R2 
MOV R2,A 
POP ACC 
MOV R1,A 
POP ACC 
MOV R0,A 
MOV A,R2 ;計算商的階碼 
CLR C 
SUBB A,R5 
LCALL MD ;階碼檢驗 
LJMP RLN ;規格化 
; (6) 標號: FCLR 功能:浮點數清零 
;入口條件:操作數在[R0]中。 
;出口信息:操作數被清零。 
;影響資源:A 堆棧需求: 2位元組 
FCLR: INC R0 
INC R0 
CLR A 
MOV @R0,A 
DEC R0 
MOV @R0,A 
DEC R0 
MOV @R0,#41H 
RET 
; (7) 標號: FZER 功能:浮點數判零 
;入口條件:操作數在[R0]中。 
;出口信息:若累加器A為零,則操作數[R0]為零,否則不為零。 
;影響資源:A 堆棧需求: 2位元組 
FZER: INC R0 
INC R0 
MOV A,@R0 
DEC R0 
ORL A,@R0 
DEC R0 
JNZ ZERO 
MOV @R0,#41H 
ZERO: RET 
; (8) 標號: FMOV 功能:浮點數傳送 
;入口條件:源操作數在[R1]中,目標地址為[R0]。 
;出口信息:[R0]=[R1],[R1]不變。 
;影響資源:A 堆棧需求: 2位元組 
FMOV: INC R0 
INC R0 
INC R1 
INC R1 
MOV A,@R1 
MOV @R0,A 
DEC R0 
DEC R1 
MOV A,@R1 
MOV @R0,A 
DEC R0 
DEC R1 
MOV A,@R1 
MOV @R0,A 
RET 
; (8.1) 標號: FMOVR0 功能:浮點數傳送 
;入口條件:源操作數在[R0]中,目標地址為[R1]。 
;出口信息:[R1]=[R0],[R0]不變。 
;影響資源:A 堆棧需求: 2位元組 
FMOVR0: INC R1 
INC R1 
INC R0 
INC R0 
MOV A,@R0 
MOV @R1,A 
DEC R1 
DEC R0 
MOV A,@R0 
MOV @R1,A 
DEC R1 
DEC R0 
MOV A,@R0 
MOV @R1,A 
RET 
; (24)標號: DTOF 功能:雙位元組十六進制定點數轉換成格式化浮點數 
;入口條件:雙位元組定點數的絕對值在[R0]中,數符在位1FH中,整數部分的位數在A中。 
;出口信息:轉換成格式化浮點數在[R0]中(三位元組)。 
;影響資源:PSW、A、R2、R3、R4、位1FH 堆棧需求: 6位元組 
DTOF: MOV R2,A ;按整數的位數初始化階碼 
MOV A,@R0 ;將定點數作尾數 
MOV R3,A 
INC R0 
MOV A,@R0 
MOV R4,A 
DEC R0 
LCALL RLN ;進行規格化 
LJMP MOV0 ;傳送結果到[R0]中 
; (25) 標號: FTOD 功能:格式化浮點數轉換成雙位元組定點數 
;入口條件:格式化浮點操作數在[R0]中。 
;出口信息:OV=1時溢出,OV=0時轉換成功:定點數的絕對值在[R0]中(雙位元組),數符 
;在位1FH中,F0=1 時為整數,CY=1時為一位元組整數一位元組小數,否則為純小數。 
;影響資源:PSW、A、B、R2、R3、R4、位1FH 堆棧需求: 6位元組 
FTOD: LCALL MVR0 ;將[R0]傳送到第一工作區 
MOV A,R2 
JZ FTD4 ;階碼為零,純小數 
JB ACC.7,FTD4;階碼為負,純小數 
SETB C 
SUBB A,#10H 
JC FTD1 
SETB OV ;階碼大於16,溢出 
RET 
FTD1: SETB C 
MOV A,R2 
SUBB A,#8 ;階碼大於8否? 
JC FTD3 
FTD2: MOV B,#10H ;階碼大於8,按雙位元組整數轉換 
LCALL FTD8 
SETB F0 ;設立雙位元組整數標志 
CLR C 
CLR OV 
RET 
FTD3: MOV B,#8 ;按一位元組整數一位元組小數轉換 
LCALL FTD8 
SETB C ; 設立一位元組整數一位元組小數標志 
CLR F0 
CLR OV 
RET 
FTD4: MOV B,#0 ;按純小數轉換 
LCALL FTD8 
CLR OV ;設立純小數標志 
CLR F0 
CLR C 
RET 
FTD8: MOV A,R2 ;按規定的整數位數進行右規***階碼是擴展後的值 
CJNE A,B,FTD9 
MOV A,R3 ;將雙位元組結果傳送到[R0]中 
MOV @R0,A 
INC R0 
MOV A,R4 
MOV @R0,A 
DEC R0 
RET 
FTD9: CLR C 
LCALL RR1 ;右規一次 
SJMP FTD8 
; (26) 標號: BTOF 功能:浮點BCD碼轉換成格式化浮點數 
;入口條件:浮點BCD碼操作數在[R0]中。 
;出口信息:轉換成的格式化浮點數仍在[R0]中。 
;影響資源:PSW、A、B、R2~R7、位1DH~1FH 堆棧需求:6位元組 
BTOF: INC R0 ;判斷是否為零。 
INC R0 
MOV A,@R0 
MOV R7,A 
DEC R0 
MOV A,@R0 
MOV R6,A 
DEC R0 
ORL A,R7 
JNZ BTF0 
MOV @R0,#41H;為零,轉換結束。 
RET 
BTF0: MOV A,@R0 
MOV C,ACC.7 
MOV 1DH,C ;保存數符。 
CLR 1FH ;以絕對值進行轉換。 
MOV C,ACC.6 ;擴充階碼為八位。 
MOV ACC.7,C 
MOV @R0,A 
JNC BTF1 
ADD A,#19 ;是否小於1E-19? 
JC BTF2 
MOV @R0,#41H ;小於1E-19時以0計。 
INC R0 
MOV @R0,#0 
INC R0 
MOV @R0,#0 
DEC R0 
DEC R0 
RET 
BTF1: SUBB A,#19 
JC BTF2 
MOV A,#3FH ;大於1E19時封頂。 
MOV C,1DH 
MOV ACC.7,C 
MOV @R0,A 
INC R0 
MOV @R0,#0FFH 
INC R0 
MOV @R0,#0FFH 
DEC R0 
DEC R0 
RET 
BTF2: CLR A ;准備將BCD碼尾數轉換成十六進制浮點數。 
MOV R4,A 
MOV R3,A 
MOV R2,#10H ;至少兩個位元組。 
BTF3: MOV A,R7 
ADD A,R7 
DA A 
MOV R7,A 
MOV A,R6 
ADDC A,R6 
DA A 
MOV R6,A 
MOV A,R4 
RLC A 
MOV R4,A 
MOV A,R3 
RLC A 
MOV R3,A 
DEC R2 
JNB ACC.7,BTF3;直到尾數規格化。 
MOV A,R6 ;四捨五入。 
ADD A,#0B0H ; ******加#80H,也可以 
CLR A 
ADDC A,R4 
MOV R4,A 
CLR A 
ADDC A,R3 
MOV R3,A 
JNC BTF4 
MOV R3,#80H ; ****有進位右規一次 
INC R2 
BTF4: MOV DPTR,#BTFL;准備查表得到十進制階碼對應的浮點數。 
MOV A,@R0 
ADD A,#19 ;計算表格偏移量。 
MOV B,#3 
MUL AB 
ADD A,DPL 
MOV DPL,A 
JNC BTF5 
INC DPH 
BTF5: CLR A ;查表。 
MOVC A,@A+DPTR 
MOV C,ACC.6 
MOV ACC.7,C 
MOV R5,A 
MOV A,#1 
MOVC A,@A+DPTR 
MOV R6,A 
MOV A,#2 
MOVC A,@A+DPTR 
MOV R7,A 
LCALL MUL1 ;將階碼對應的浮點數和尾數對應的浮點數相乘。 
MOV C,1DH ;取出數符。 
MOV 1FH,C 
LJMP MOV0 ;傳送轉換結果。 
; (27) 標號: FTOB 功能:格式化浮點數轉換成浮點BCD碼 
;入口條件:格式化浮點操作數在[R0]中。 
;出口信息:轉換成的浮點BCD碼仍在[R0]中。 
;影響資源:PSW、A、B、R2~R7、位1DH~1FH 堆棧需求:6位元組 
FTOB: INC R0 
MOV A,@R0 
INC R0 
ORL A,@R0 
DEC R0 
DEC R0 
JNZ FTB0 
MOV @R0,#41H 
RET 
FTB0: MOV A,@R0 
MOV C,ACC.7 
MOV 1DH,C 
CLR ACC.7 
MOV @R0,A 
LCALL MVR0 
MOV DPTR,#BFL0;絕對值大於或等於1時的查表起點。 
MOV B,#0 ;十的0次冪。 
MOV A,R2 
JNB ACC.7,FTB1 
MOV DPTR,#BTFL;絕對值小於1E-6時的查表起點。 
MOV B,#0EDH ;十的-19次冪。 
ADD A,#16 
JNC FTB1 
MOV DPTR,#BFLN;絕對值大於或等於1E-6時的查表起點。 
MOV B,#0FAH ;十的-6次冪。 
FTB1: CLR A ;查表,找到一個比待轉換浮點數大的整數冪。 
MOVC A,@A+DPTR 
MOV C,ACC.6 
MOV ACC.7,C 
MOV R5,A 
MOV A,#1 
MOVC A,@A+DPTR 
MOV R6,A 
MOV A,#2 
MOVC A,@A+DPTR 
MOV R7,A 
MOV A,R5 ;和待轉換浮點數比較。 
CLR C 
SUBB A,R2 
JB ACC.7,FTB2;差為負數。 
JNZ FTB3 
MOV A,R6 
CLR C 
SUBB A,R3 
JC FTB2 
JNZ FTB3 
MOV A,R7 
CLR C 
SUBB A,R4 
JC FTB2 
JNZ FTB3 
MOV R5,B ;正好是表格中的數。 
INC R5 ;冪加一。 
MOV R6,#10H ;尾數為0·1000。 
MOV R7,#0 
SJMP FTB6 ;傳送轉換結果。 
FTB2: INC DPTR ;准備表格下一項。 
INC DPTR 
INC DPTR 
INC B ;冪加一。 
SJMP FTB1 ; 
FTB3: PUSH B ;保存冪值。 
LCALL DIV3 ;相除,得到一個二進制浮點數的純小數。 
FTB4: MOV A,R2 ;取階碼。 
JZ FTB5 ;為零嗎? 
CLR C ; 
LCALL RR1 ;右規。 
SJMP FTB4 
FTB5: POP ACC ;取出冪值。 
MOV R5,A ;作為十進制浮點數的階碼。 
LCALL HB2 ;轉換尾數的十分位和百分位。 
MOV R6,A 
LCALL HB2 ;轉換尾數的千分位和萬分位。 
MOV R7,A 
MOV A,R3 ;四捨五入。 
RLC A 
CLR A 
ADDC A,R7 
DA A 
MOV R7,A 
CLR A 
ADDC A,R6 
DA A 
MOV R6,A 
JNC FTB6 
MOV R6,#10H 
INC R5 
FTB6: INC R0 ;存放轉換結果。 
INC R0 
MOV A,R7 
MOV @R0,A 
DEC R0 
MOV A,R6 
MOV @R0,A 
DEC R0 
MOV A,R5 
MOV C,1DH ;取出數符。 
MOV ACC.7,C 
MOV @R0,A 
RET 
HB2: MOV A,R4 ; 尾數擴大100倍。 
MOV B,#100 
MUL AB 
MOV R4,A 
MOV A,B 
XCH A,R3 
MOV B,#100 
MUL AB 
ADD A,R3 
MOV R3,A 
JNC HB21 
INC B 
HB21: MOV A,B ;將整數部分轉換成BCD碼。 
MOV B,#10 
DIV AB 
SWAP A 
ORL A,B 
RET 
BTFL: DB 41H,0ECH,1EH ;1.0000E-19 
DB 45H,93H,93H ;1.0000E-18 
DB 48H,0B8H,78H ;1.0000E-17 
DB 4BH,0E6H,96H ;1.0000E-16 
DB 4FH,90H,1DH ;1.0000E-15 
DB 52H,0B4H,25H ;1.0000E-14 
DB 55H,0E1H,2EH ;1.0000E-13 
DB 59H,8CH,0BDH ;1.0000E-12 
DB 5CH,0AFH,0ECH ;1.0000E-11 
DB 5FH,0DBH,0E7H ;1.0000E-10 
DB 63H,89H,70H ;1.0000E-9 
DB 66H,0ABH,0CCH ;1.0000E-8 
DB 69H,0D6H,0C0H ;1.0000E-7 
BFLN: DB 6DH,86H,38H ;1.0000E-6 
DB 70H,0A7H,0C6H ;1.0000E-5 
DB 73H,0D1H,0B7H ;1.0000E-4 
DB 77H,83H,12H ;1.0000E-3 
DB 7AH,0A3H,0D7H ;1.0000E-2 
DB 7DH,0CCH,0CDH ;1.0000E-1 
BFL0: DB 1,80H,00H ;1.0000 
DB 4,0A0H,00H ;;1.0000E1 
DB 7,0C8H,00H ;1.0000E2 
DB 0AH,0FAH,00H ;1.0000E3 
DB 0EH,9CH,40H ;1.0000E4 
DB 11H,0C3H,50H ;1.0000E5 
DB 14H,0F4H,24H ;1.0000E6 
DB 18H,98H,97H ;1.0000E7 
DB 1BH,0BEH,0BCH ;1.0000E8 
DB 1EH,0EEH,6BH ;1.0000E9 
DB 22H,95H,03H ;1.0000E10 
DB 25H,0BAH,44H ;1.0000E11 
DB 28H,0E8H,0D5H ;1.0000E12 
DB 2CH,91H,85H ; 1.0000E13 
DB 2FH,0B5H,0E6H ;1.0000E14 
DB 32H,0E3H,60H ;1.0000E15 
DB 36H,8EH,1CH ;1.0000E16 
DB 39H,31H,0A3H ;1.0000E17 
DB 3CH,0DEH,0BH ;1.0000E18 
DB 40H,8AH,0C7H ;1.0000E19
『貳』 vb 匯編 jmp 函數問題
這個怎麼說呢?在同一機器里,這個地址一般不變,因為是系統DLL嘛,不同的系統就可能不一樣了,所以要這樣(VB我是不會的,用C來吧,不過VB可不以這樣用API我就不知道了): 
定義數據: 
char szMoleName[]="USER32.dll",0 ; 
char szProcName[]="MessageBoxA",0 ; 
int hInstance ; 
int lpProcAddress; 
程序主要部分是: 
hInstance=GetMoleHandle(offset szMoleName) 
lpProcAddress=GetProcessAddress(hInstance,offset szProcName); 
jmp lpProcAddress 
如果要保險一點就多用個loadlibraryA吧。
Address = GetProcAddress(GetMoleHandle("user32.dll"), "MessageBoxA") 
這樣也行,GetMoleHandle這樣的API不是要傳地址指針嗎?VB好像沒指針,你就用這個"MessageBoxA" 是嗎?
用匯編是這樣的:
With asm ' asm 
.push o
.push lpfnCoption
.push lpfnText
.push hInstance
With asm ' asm 
.Mov_EAX Address 
.CALL_EAX 
End With
『叄』 每次剛啟動完電腦,我就發現在進程中有很多的svchost.exe,這是不是病毒啊
Svchost.exe是病毒的兩種情況
1.利用假冒Svchost.exe名稱的病毒程序 
這種方式運行的病毒並沒有直接利用真正的Svchost.exe進程,而是啟動了另外一個名稱同樣是Svchost.exe的病毒進程,由於這個假冒的病毒進程並沒有載入系統服務,它和真正的Svchost.exe進程是不同的,只需在命令行窗口中運行一下「Tasklist /svc」,如果看到哪個Svchost.exe進程後面提示的服務信息是「暫缺」,而不是一個具體的服務名,那麼它就是病毒進程了,記下這個病毒進程對應的PID數值(進程標識符),即可在任務管理器的進程列表中找到它,結束進程後,在C盤搜索Svchost.exe文件,也可以用第三方進程工具直接查看該進程的路徑,正常的Svchost.exe文件是位於%systemroot%\System32目錄中的,而假冒的Svchost.exe病毒或木馬文件則會在其他目錄,例如「w32.welchina.worm」病毒假冒的Svchost.exe就隱藏在Windows\System32\Wins目錄中,將其刪除,並徹底清除病毒的其他數據即可。 
2:一些高級病毒則採用類似系統服務啟動的方式,通過真正的Svchost.exe進程載入病毒程序,而Svchost.exe是通過注冊表數據來決定要裝載的服務列表的,所以病毒通常會在注冊表中採用以下方法進行載入: 
添加一個新的服務組,在組里添加病毒服務名 
在現有的服務組里直接添加病毒服務名 
修改現有服務組里的現有服務屬性,修改其「ServiceDll」鍵值指向病毒程序 
判斷方法:病毒程序要通過真正的Svchost.exe進程載入,就必須要修改相關的注冊表數據,可以打開[HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Svchost],觀察有沒有增加新的服務組,同時要留意服務組中的服務列表,觀察有沒有可疑的服務名稱,通常來說,病毒不會在只有一個服務名稱的組中添加,往往會選擇LocalService和netsvcs這兩個載入服務較多的組,以干擾分析,還有通過修改服務屬性指向病毒程序的,通過注冊表判斷起來都比較困難,這時可以利用前面介紹的服務管理專家,分別打開LocalService和netsvcs分支,逐個檢查右邊服務列表中的服務屬性,尤其要注意服務描述信息全部為英文的,很可能是第三方安裝的服務,同時要結合它的文件描述、版本、公司等相關信息,進行綜合判斷。例如這個名為PortLess BackDoor的木馬程序,在服務列表中可以看到它的服務描述為「Intranet Services」,而它的文件版本、公司、描述信息更全部為空,如果是微軟的系統服務程序是絕對不可能出現這種現象的。從啟動信息「C:\WINDOWS\System32\svchost.exe -k netsvcs」中可以看出這是一款典型的利用Svchost.exe進程載入運行的木馬,知道了其原理,清除方法也很簡單了:先用服務管理專家停止該服務的運行,然後運行regedit.exe打開「注冊表編輯器」,刪除[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\IPRIP]主鍵,重新啟動計算機,再刪除%systemroot%\System32目錄中的木馬源程序「svchostdll.dll」,通過按時間排序,又發現了時間完全相同的木馬安裝程序「PortlessInst.exe」,一並刪除即可。
svchost.exe是nt核心系統的非常重要的進程,對於2000、xp來說,不可或缺。很多病毒、木馬也會調用它。所以,深入了解這個程序,是玩電腦的必修課之一。
  大家對windows操作系統一定不陌生,但你是否注意到系統中「svchost.exe」這個文件呢?細心的朋友會發現windows中存在多個 「svchost」進程(通過「ctrl+alt+del」鍵打開任務管理器,這里的「進程」標簽中就可看到了),為什麼會這樣呢?下面就來揭開它神秘的面紗。
發現
  在基於nt內核的windows操作系統家族中,不同版本的windows系統,存在不同數量的「svchost」進程,用戶使用「任務管理器」可查看其進程數目。一般來說,win2000有兩個svchost進程,winxp中則有四個或四個以上的svchost進程(以後看到系統中有多個這種進程,千萬別立即判定系統有病毒了喲),而win2003 server中則更多。這些svchost進程提供很多系統服務,如:rpcss服務(remote procere call)、dmserver服務(logical disk manager)、dhcp服務(dhcp client)等。
  如果要了解每個svchost進程到底提供了多少系統服務,可以在win2000的命令提示符窗口中輸入「tlist -s」命令來查看,該命令是win2000 support tools提供的。在winxp則使用「tasklist /svc」命令。
svchost中可以包含多個服務
深入
  windows系統進程分為獨立進程和共享進程兩種,「svchost.exe」文件存在於「%systemroot% system32」目錄下,它屬於共享進程。隨著windows系統服務不斷增多,為了節省系統資源,微軟把很多服務做成共享方式,交由 svchost.exe進程來啟動。但svchost進程只作為服務宿主,並不能實現任何服務功能,即它只能提供條件讓其他服務在這里被啟動,而它自己卻不能給用戶提供任何服務。那這些服務是如何實現的呢?
  原來這些系統服務是以動態鏈接庫(dll)形式實現的,它們把可執行程序指向 svchost,由svchost調用相應服務的動態鏈接庫來啟動服務。那svchost又怎麼知道某個系統服務該調用哪個動態鏈接庫呢?這是通過系統服務在注冊表中設置的參數來實現。下面就以rpcss(remote procere call)服務為例,進行講解。
  從啟動參數中可見服務是靠svchost來啟動的。
實例
  以windows xp為例,點擊「開始」/「運行」,輸入「services.msc」命令,彈出服務對話框,然後打開「remote procere call」屬性對話框,可以看到rpcss服務的可執行文件的路徑為「c:\windows\system32\svchost -k rpcss」,這說明rpcss服務是依靠svchost調用「rpcss」參數來實現的,而參數的內容則是存放在系統注冊表中的。
  在運行對話框中輸入「regedit.exe」後回車,打開注冊表編輯器,找到[hkey_local_machine ]項,找到類型為「reg_expand_sz」的鍵「magepath」,其鍵值為「%systemroot%system32svchost -k rpcss」(這就是在服務窗口中看到的服務啟動命令),另外在「parameters」子項中有個名為「servicedll」的鍵,其值為「% systemroot%system32rpcss.dll」,其中「rpcss.dll」就是rpcss服務要使用的動態鏈接庫文件。這樣 svchost進程通過讀取「rpcss」服務注冊表信息,就能啟動該服務了。
解惑
  因為svchost進程啟動各種服務,所以病毒、木馬也想盡辦法來利用它,企圖利用它的特性來迷惑用戶,達到感染、入侵、破壞的目的(如沖擊波變種病毒「w32.welchia.worm」)。但windows系統存在多個svchost進程是很正常的,在受感染的機器中到底哪個是病毒進程呢?這里僅舉一例來說明。
  假設windows xp系統被「w32.welchia.worm」感染了。正常的svchost文件存在於「c:\windows\system32」目錄下,如果發現該文件出現在其他目錄下就要小心了。「w32.welchia.worm」病毒存在於「c:\windows\system32wins」目錄中,因此使用進程管理器查看svchost進程的執行文件路徑就很容易發現系統是否感染了病毒。windows系統自帶的任務管理器不能夠查看進程的路徑,可以使用第三方進程管理軟體,如「windows優化大師」進程管理器,通過這些工具就可很容易地查看到所有的svchost進程的執行文件路徑,一旦發現其執行路徑為不平常的位置就應該馬上進行檢測和處理。
  由於篇幅的關系,不能對svchost全部功能進行詳細介紹,這是一個windows中的一個特殊進程,有興趣的可參考有關技術資料進一步去了解它。
大家都要知道Svchost.exe,是系統必不可少的一個進程,很多服務都會多多少少用到它, 
  但是我想大家也知道,由於它本身特殊性,高明的"黑客們"肯定是不會放過的,前段時間的Svchost.exe木馬風波,大家應該是記憶猶新吧,而且現在還是有很多機器里都藏有此木馬,因為它偽裝和系統進程Svchost.exe一樣,所以很多人分不清,那個是進程,那個是木馬....
  好的,還是讓我們詳盡了解一下Svchost.exe進程吧
  1.多個服務共享一個 Svchost.exe進程利與弊 
  windows 系統服務分為獨立進程和共享進程兩種,在windows NT時只有伺服器管理器SCM(Services.exe)有多個共享服務,隨著系統內置服務的增加,在windows 2000中ms又把很多服務做成共享方式,由svchost.exe啟動。windows 2000一般有2個svchost進程,一個是RPCSS(Remote Procere Call)服務進程,另外一個則是由很多服務共享的一個svchost.exe。而在windows XP中,則一般有4個以上的svchost.exe服務進程,windows 2003 server中則更多,可以看出把更多的系統內置服務以共享進程方式由svchost啟動是ms的一個趨勢。這樣做在一定程度上減少了系統資源的消耗,不過也帶來一定的不穩定因素,因為任何一個共享進程的服務因為錯誤退出進程就會導致整個進程中的所有服務都退出。另外就是有一點安全隱患,首先要介紹一下svchost.exe的實現機制。 
  
  2. Svchost原理
  Svchost本身只是作為服務宿主,並不實現任何服務功能,需要Svchost啟動的服務以動態鏈接庫形式實現,在安裝這些服務時,把服務的可執行程序指向svchost,啟動這些服務時由svchost調用相應服務的動態鏈接庫來啟動服務。
  
  那麼svchost如何知道某一服務是由哪個動態鏈接庫負責呢?這不是由服務的可執行程序路徑中的參數部分提供的,而是服務在注冊表中的參數設置的,注冊表中服務下邊有一個Parameters子鍵其中的ServiceDll表明該服務由哪個動態鏈接庫負責。並且所有這些服務動態鏈接庫都必須要導出一個ServiceMain()函數,用來處理服務任務。
  
  例如rpcss(Remote Procere Call)在注冊表中的位置是 HKEY_LOCAL_,它的參數子鍵Parameters里有這樣一項:
  "ServiceDll"=REG_EXPAND_SZ:"%SystemRoot%system32 pcss.dll"
  當啟動rpcss服務時,svchost就會調用rpcss.dll,並且執行其ServiceMain()函數執行具體服務。
  
  既然這些服務是使用共享進程方式由svchost啟動的,為什麼系統中會有多個svchost進程呢?ms把這些服務分為幾組,同組服務共享一個svchost進程,不同組服務使用多個svchost進程,組的區別是由服務的可執行程序後邊的參數決定的。
  
  例如rpcss在注冊表中 HKEY_LOCAL_ 有這樣一項:
  "ImagePath"=REG_EXPAND_SZ:"%SystemRoot%system32svchost -k rpcss"
  因此rpcss就屬於rpcss組,這在服務管理控制台也可以看到。
  
  svchost的所有組和組內的所有服務都在注冊表的如下位置: HKEY_LOCAL_ NTCurrentVersionSvchost,例如windows 2000共有4組rpcss、netsvcs、wugroup、BITSgroup,其中最多的就是netsvcs=REG_MULTI_SZ:EventSystem.Ias.Iprip.Irmon.Netman.
  
  Nwsapagent.Rasauto.Rasman.Remoteaccess.SENS.Sharedaccess.Tapisrv.Ntmssvc.wzcsvc..
  
  在啟動一個svchost.exe負責的服務時,服務管理器如果遇到可執行程序內容ImagePath已經存在於服務管理器的映象庫中,就不在啟動第2個進程svchost,而是直接啟動服務。這樣就實現了多個服務共享一個svchost進程。
  
  3. Svchost代碼
  現在我們基本清楚svchost的原理了,但是要自己寫一個DLL形式的服務,由svchost來啟動,僅有上邊的信息還有些問題不是很清楚。比如我們在導出的ServiceMain()函數中接收的參數是ANSI還是Unicode?我們是否需要調用RegisterServiceCtrlHandler和StartServiceCtrlDispatcher來注冊服務控制及調度函數?
  
  這些問題要通過查看svchost代碼獲得。下邊的代碼是windows 2000+ service pack 4 的svchost反匯編片段,可以看出svchost程序還是很簡單的。
  
  主函數首先調用ProcCommandLine()對命令行進行分析,獲得要啟動的服務組,然後調用SvcHostOptions()查詢該服務組的選項和服務組的所有服務,並使用一個數據結構 svcTable 來保存這些服務及其服務的DLL,然後調用PrepareSvcTable() 函數創建 SERVICE_TABLE_ENTRY 結構,把所有處理函數SERVICE_MAIN_FUNCTION 指向自己的一個函數FuncServiceMain(),最後調用API StartServiceCtrlDispatcher() 注冊這些服務的調度函數。 
  
  ; =============================== Main Funcion =======================================
  .text:010010B8 public start
  .text:010010B8 start proc near
  .text:010010B8 push esi
  .text:010010B9 push edi
  .text:010010BA push offset sub_1001EBA ; lpTopLevelExceptionFilter
  .text:010010BF xor edi, edi
  .text:010010C1 call ds:SetUnhandledExceptionFilter
  .text:010010C7 push 1 ; uMode
  .text:010010C9 call ds:SetErrorMode
  .text:010010CF call ds:GetProcessHeap
  .text:010010D5 push eax
  .text:010010D6 call sub_1001142
  .text:010010DB mov eax, offset dword_1003018
  .text:010010E0 push offset unk_1003000 ; lpCriticalSection
  .text:010010E5 mov dword_100301C, eax
  .text:010010EA mov dword_1003018, eax
  .text:010010EF call ds:InitializeCriticalSection
  .text:010010F5 call ds:GetCommandLineW
  .text:010010FB push eax ; lpString
  .text:010010FC call ProcCommandLine
  .text:01001101 mov esi, eax
  .text:01001103 test esi, esi
  .text:01001105 jz short lab_doservice
  .text:01001107 push esi
  .text:01001108 call SvcHostOptions
  .text:0100110D call PrepareSvcTable
  .text:01001112 mov edi, eax ; SERVICE_TABLE_ENTRY returned
  .text:01001114 test edi, edi
  .text:01001116 jz short loc_1001128
  .text:01001118 mov eax, [esi+10h]
  .text:0100111B test eax, eax
  .text:0100111D jz short loc_1001128
  .text:0100111F push dword ptr [esi+14h] ; dwCapabilities
  .text:01001122 push eax ; int
  .text:01001123 call InitializeSecurity
  .text:01001128 
  .text:01001128 loc_1001128: ; CODE XREF: start+5Ej
  .text:01001128 ; start+65j
  .text:01001128 push esi ; lpMem
  .text:01001129 call HeapFreeMem
  .text:0100112E 
  .text:0100112E lab_doservice: ; CODE XREF: start+4Dj
  .text:0100112E test edi, edi
  .text:01001130 jz ExitProgram
  .text:01001136 push edi ; lpServiceStartTable
  .text:01001137 call ds:StartServiceCtrlDispatcherW
  .text:0100113D jmp ExitProgram
  .text:0100113D start endp
  ; =============================== Main Funcion end ===========================================
  
  由於svchost為該組的所有服務都注冊了svchost中的一個處理函數,因此每次啟動任何一個服務時,服務管理器SCM都會調用FuncServiceMain() 這個函數。這個函數使用 svcTable 查詢要啟動的服務使用的DLL,調用DLL導出的ServiceMain()函數來啟動服務,然後返回。 
  ; ============================== FuncServiceMain() ===========================================
  .text:01001504 FuncServiceMain proc near ; DATA XREF: PrepareSvcTable+44o
  .text:01001504 
  .text:01001504 arg_0 = dword ptr 8
  .text:01001504 arg_4 = dword ptr 0Ch
  .text:01001504 
  .text:01001504 push ecx
  .text:01001505 mov eax, [esp+arg_4]
  .text:01001509 push ebx
  .text:0100150A push ebp
  .text:0100150B push esi
  .text:0100150C mov ebx, offset unk_1003000
  .text:01001511 push edi
  .text:01001512 mov edi, [eax]
  .text:01001514 push ebx
  .text:01001515 xor ebp, ebp
  .text:01001517 call ds:EnterCriticalSection
  .text:0100151D xor esi, esi
  .text:0100151F cmp dwGroupSize, esi
  .text:01001525 jbe short loc_1001566
  .text:01001527 and [esp+10h], esi
  .text:0100152B 
  .text:0100152B loc_100152B: ; CODE XREF: FuncServiceMain+4Aj
  .text:0100152B mov eax, svcTable
  .text:01001530 mov ecx, [esp+10h]
  .text:01001534 push dword ptr [eax+ecx]
  .text:01001537 push edi
  .text:01001538 call ds:lstrcmpiW
  .text:0100153E test eax, eax
  .text:01001540 jz short StartThis
  .text:01001542 add dword ptr [esp+10h], 0Ch
  .text:01001547 inc esi
  .text:01001548 cmp esi, dwGroupSize
  .text:0100154E jb short loc_100152B
  .text:01001550 jmp short loc_1001566
  .text:01001552 ; =================================================
  .text:01001552 
  .text:01001552 StartThis: ; CODE XREF: FuncServiceMain+3Cj
  .text:01001552 mov ecx, svcTable
  .text:01001558 lea eax, [esi+esi*2]
  .text:0100155B lea eax, [ecx+eax*4]
  .text:0100155E push eax
  .text:0100155F call GetDLLServiceMain
  .text:01001564 mov ebp, eax ; dll ServiceMain Function address
  .text:01001566 
  .text:01001566 loc_1001566: ; CODE XREF: FuncServiceMain+21j
  .text:01001566 ; FuncServiceMain+4Cj
  .text:01001566 push ebx
  .text:01001567 call ds:LeaveCriticalSection
  .text:0100156D test ebp, ebp
  .text:0100156F jz short loc_100157B
  .text:01001571 push [esp+10h+arg_4]
  .text:01001575 push [esp+14h+arg_0]
  .text:01001579 call ebp
  .text:0100157B 
  .text:0100157B loc_100157B: ; CODE XREF: FuncServiceMain+6Bj
  .text:0100157B pop edi
  .text:0100157C pop esi
  .text:0100157D pop ebp
  .text:0100157E pop ebx
  .text:0100157F pop ecx
  .text:01001580 retn 8
  .text:01001580 FuncServiceMain endp ; sp = -8
  ; ============================== FuncServiceMain() end ========================================
  
  由於svchost已經調用了StartServiceCtrlDispatcher來服務調度函數,因此我們在實現DLL實現時就不用了,這主要是因為一個進程只能調用一次StartServiceCtrlDispatcher API。但是需要用 RegisterServiceCtrlHandler 來注冊響應控制請求的函數。最後我們的DLL接收的都是unicode字元串。
  
  由於這種服務啟動後由svchost載入,不增加新的進程,只是svchost的一個DLL,而且一般進行審計時都不會去HKEY_LOCAL_ NTCurrentVersionSvchost 檢查服務組是否變化,就算去檢查,也不一定能發現異常,因此如果添加一個這樣的DLL後門,偽裝的好,是比較隱蔽的。
  
  4. 安裝服務與設置
  要通過svchost調用來啟動的服務,就一定要在HKEY_LOCAL_ NTCurrentVersionSvchost下有該服務名,這可以通過如下方式來實現:
  1) 添加一個新的服務組,在組里添加服務名
  2) 在現有組里添加服務名
  3) 直接使用現有服務組里的一個服務名,但本機沒有安裝的服務
  4) 修改現有服務組里的現有服務,把它的ServiceDll指向自己
  
  其中前兩種可以被正常服務使用,如使用第1種方式,啟動其服務要創建新的svchost進程;第2種方式如果該組服務已經運行,安裝後不能立刻啟動服務,因為svchost啟動後已經把該組信息保存在內存里,並調用API StartServiceCtrlDispatcher() 為該組所有服務注冊了調度處理函數,新增加的服務不能再注冊調度處理函數,需要重起計算機或者該組的svchost進程。而後兩種可能被後門使用,尤其是最後一種,沒有添加服務,只是改了注冊表裡一項設置,從服務管理控制台又看不出來,如果作為後門還是很隱蔽的。比如EventSystem服務,預設是指向es.dll,如果把ServiceDll改為EventSystem.dll就很難發現。
  
  因此服務的安裝除了調用CreateService()創建服務之外,還需要設置服務的ServiceDll,如果使用前2種還要設置svchost的注冊表選項,在卸載時也最好刪除增加的部分。
  
  註: ImagePath 和ServiceDll 是ExpandString不是普通字元串。因此如果使用.reg文件安裝時要注意。
  
  5. DLL服務實現
  DLL程序的編寫比較簡單,只要實現一個ServiceMain()函數和一個服務控製程序,在ServiceMain()函數里用RegisterServiceCtrlHandler()注冊服務控製程序,並設置服務的運行狀態就可以了。
  
  另外,因為此種服務的安裝除了正常的CreateService()之外,還要進行其他設置,因此最好實現安裝和卸載函數。 
  
  為了方便安裝,實現的代碼提供了InstallService()函數進行安裝,這個函數可以接收服務名作為參數(如果不提供參數,就使用預設的iprip),如果要安裝的服務不在svchost的netsvcs組里安裝就會失敗;如果要安裝的服務已經存在,安裝也會失敗;安裝成功後程序會配置服務的ServiceDll為當前Dll。提供的UninstallService()函數,可以刪除任何函數而沒有進行任何檢查。
  
  為了方便使用rundll32.exe進行安裝,還提供了RundllInstallA()和RundllUninstallA()分別調用InstallService()及UninstallService()。因為rundll32.exe使用的函數原型是:
  void CALLBACK FunctionName(
  HWND hwnd, // handle to owner window
  HINSTANCE hinst, // instance handle for the DLL
  LPTSTR lpCmdLine, // string the DLL will parse
  int nCmdShow // show state
  );
  對應的命令行是rundll32 DllName,FunctionName [Arguments] 
  
  DLL服務本身只是創建一個進程,該程序命令行就是啟動服務時提供的第一個參數,如果未指定就使用預設的svchostdll.exe。啟動服務時如果提供第二個參數,創建的進程就是和桌面交互的。
幹掉Svchost.exe進程!
  1.錯誤的解決方法描述 
  當我們按下Alt+Ctrl+Del打開任務管理器,發現進程中出現多個Svchost.exe,則表明系統中毒,我們首先將所有的Svchost結束掉,然後使用相關的殺毒工具查殺病毒。
  
  注:
  2003年的夏天,「沖擊波」病毒橫行的時候有一種說法就是Svchost.exe都是病毒,一看到就要刪除。這種說法讓電腦用戶人心惶惶,因為每個使用 Windows XP系統的用戶在按照文章中介紹的檢查有無Svchost.exe的方法都可以找到幾個Svchost.exe進程。
  
  有關Svchost.exe詳見:
  http://forum.ikaka.com/topic.asp?board=3&artid=6087605
  
  2.方案由來及後果 
  在很多人的印象中,每個應用程序一般只對應一個進程,如QQ對應QQ.EXE進程、記事本對應notepad.exe進程等。所以當看到系統有多個同樣名字的進程時,總是會將其聯想為病毒或者木馬程序在作怪。如果不加思索,野蠻的將其中的某些Svchost.exe進程結束掉,會讓系統的運行變得不穩定。
  
  3.正確的解決辦法 
  Windows 進程分為獨立進程和共享進程兩種,Svchost.exe屬於後者。Windows XP為了節約系統資源,將很多個系統服務做為共享方式由Svchost.exe來啟動。Svchost本身只是作為服務宿主,並不能實現任何服務功能, svchost通過調用相應服務的動態鏈接庫(DLL)來啟動該服務,而Windows將這些服務分為幾個組,同組的服務共享一個Svchost進程,不同的組所指向的Svchost不同。通常情況下,Windows XP有4個由Svchost啟動的服務組,也就是說Windows XP系統一般有4個Svchost.exe進程。當然某些應用程序或服務也有可能會調用Svchost,所以當你看到系統中有多餘4個的 Svchost.exe進程,也不要盲目判斷系統中了病毒。實際上Svchost.exe進程的個數跟是否中毒無直接關系。 
  
  小提示:
  ★ 筆者做了下面一個非常有趣的測試:打開任務管理器,切換到「進程」選項卡,首先手動結束掉由上到下的第三個Svchost.exe進程,結束完後系統會馬上重新建立該進程,接下來我們手動結束掉由上到下的最後一個Svchost.exe進程,系統會出現一個類似中了沖擊波病毒的對話窗口,並倒計時關機,這是由於該Svchost.exe進程引導RPC服務,終止該進程則導致RPC服務中斷,系統自然會重新啟動了。 
  ★Windows 2000中一般有兩個Svchost.exe進程,Windows Server 2003則非常多,一般有6個。 
  
  既然系統中Svchost.exe進程數與是否中毒無關,我們究竟如何區別正常的和病毒偽造的Svchost進程呢?
  我們可以使用下面兩種方法來鑒別:
  方法一:
  在系統所在分區進行搜索,如果發現多個Svchost.exe文件,則系統很有可能中毒。正常的Svchost.exe位於%windir%\\ system32目錄下,如果發現其它目錄中有Svchost.exe文件,你就要小心了。例如沖擊波的變種Win32.Welchia.Worm會在% windir%\\system32\\wins目錄種下Svchost.exe文件。
  方法二:
  察看Svchost.exe進程對應文件的路徑。
  Windows XP自帶的任務管理器中無法察看,我們需要藉助第三方工具,例如Windows優化大師自帶的進程管理工具,運行它後定
