PersonalCorpus 版 (精华区)

发信人: lofe ()感激生活(), 信区: Hacker
标  题: 微机BIOS口令破译与设置
发信站: 哈工大紫丁香 (Tue Sep  5 19:20:32 2000), 转信

        微机BIOS口令破译与设置
                        华中理工大学CAD中心

        本文详细阐述了海洋主板、DECpc主板(Digital公司)和AMI主板的口令加密算法与解密算法,用到了计算CMOS校验和的算法,并给出了破译口令和修改口令的程序。
                一、海洋主板
        海洋主板口令最多由10个字符构成,加密后只生成一个16位的密码,存储在CMOS单元3AH和3BH。口令检查方式存储于3CH单元的最高二位,00表示disable, 01表示setup only, 10表示 Powerup&Setup,11表示Bootup&Setup。口令加密算法如下:
        设      
        口令长度为  L   L≤10   
        明文口令为  Y={y1, y2, ... , yL}
        加密因子为  K={k0, k1, ... , kL}       其中k0=FFFFH
        密文口令为  M
        则      ki= f(ki-1, yi)   1≤i≤L
                M= kL
        加密函数   ki= f(ki-1, yi) 定义为:
        设      yi={Bit0, Bit1 , ... , Bit14 ,Bit15 },
                 明文yi由ASCII码加扫描码构成 ,故有16位。
        则      S0= ki-1
                Sj+1 = ( Sj * 2  + Bitj ) XOR 1021H  如果Sj AND 8000H >0    
                Sj+1 = ( Sj * 2  + Bitj )               如果Sj AND 8000H =0
                                        (0≤j≤15)
                ki= S16
         通过对加密过程分析可知,加密函数是多对一函数,即多个明文对应一个密文。这说明海洋微机可能有多个口令。因此,加密过程不可逆,解密算法只能是穷举法。
                二、DECpc主板
        DECpc主板口令最多由7个字符构成 ,经加密变换后存储于CMOS单元58H-5EH,5FH单元存储口令扫描码的字节累加和。加密算法比较简单,算法如下:
        设      
        口令长度为  L   L≤7
        明文口令为  Y={y1, y2, ... , yL}
        密文口令为  M={m1, m2, ... , mL}
        则
                mi = ROR( yi XOR AAH, 7- i )    1≤i≤L
        其中ROR为循环右移函数。
        解密函数为:
                yi = ROL( mi , 7- i ) XOR AAH           1≤i≤L
        其中ROL为循环左移函数。
                三、AMI主板
        AMI主板口令可由6个字符构成 ,加密后存储于CMOS单元38H-3DH,37单元存储加密算法的加密因子,是随机生成的。故多次设置的同一口令的密文并不相同。
        设 
        口令长度为  L   L≤6
        明文口令为  Y={y1, y2, ... , yL}
        加密因子为  m0
        密文口令为  M={m1, m2, ... , mL}
        则      mi= f(mi-1, yi)   1≤i≤L
        加密函数   mi=f(mi-1, yi) 定义为:
                S0=mi-1
                Sj+1 =Sj / 2 + 80H      如果 Sj AND C3H 的奇偶性为奇
                Sj+1 =Sj / 2            如果 Sj AND C3H 的奇偶性为偶
                                (0≤j ≤yi )
                mi= Syi+1
        解密算法不再列出。

                        加密算法比较            
主板类型        特征字符串      密文存储单元    口令长度        校验和1 校验和2 允许/禁止单元   多个口令
MR       'MR BIOS'      3A-3B   10      2E,2F   3F      3C  bit6,bit7   是
DECpc    'DECpc'        58-5E   7       2E,2F   5F      N/A     否
AMI      'AMMMMI'       38-3D   6       2E,2F   3E,3F   34  bit6        否
Phoenix  'Phoenix'      27-28,  29-2A   7       2E,2F   6E,6F,70        55  bit4        是

        以上算法省略了与扫描码有关的细节。据此,笔者编写了针对三种主板的口令破译与修改程序PWD.CPP。程序首先自动识别主板类型,在BIOS段F000H中搜索能代表主板的特征字符串。DECpc主板也包含字符串'Phoenix', 
但是优先寻找'DECpc'。然后根据主板类型调用不同的解密算法,显示机器BIOS口令。对海洋微机可求出多个口令,用户输入任一口令即可使用该机器。还能直接修改BIOS口令,对于海洋主板和AMI主板,修改口令后需重新计算CMOS校验和,算法详见程序。本程序在多台微机上测试通过。

 //      Filename PWD.CPP
//      (C) Copyright SunJian  CAD Center, HUST.  All Rights Reserved
//      Compile with   SMALL model   Tel:7543973
/************************************************************
function  : Show your CMOS password
date      : 1994 11 11
Modify    : 1996 3 2
************************************************************/
#ifndef __SMALL__
#error complile with small model
#endif
#include <stdio.h>
#include <conio.h>
#include <bios.h>
#include <dos.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#define INDEX 0x70
#define VALUE 0x71
#define BYTE unsigned char
#define WORD unsigned int

void help();
void display();
void wbyte(int port, unsigned value);
BYTE rbyte(int port);
void cal_checksum( int checklen);
int  write_mrsum();
int  write_amisum();
void change_bios();
int  test_biostype(void);

void show_mrpassword();
void change_mrpassword(char*);
void show_dec_password();
void change_dec_password(char*);
void show_ami_password();
void change_ami_password(char*);
//void show_phoenix_password();

WORD scan_code[]={    
    0, 0x1e61,0x3062,0x2e63,0x2064,0x1265,
    0x2166,0x2267,0x2368,0x1769,0x246a,
    0x256b,0x266c,0x326d,0x316e,0x186f,
    0x1970,0x1071,0x1372,0x1f73,0x1474,
    0x1675,0x2f76,0x1177,0x2d78,0x1579,
    0x2c7a,
    0x0231,0x0332,0x0433,0x0534,0x0635,
    0x0736,0x0837,0x0938,0x0a39,0x0b30,
    0x0c2d,0x0d3d,0x0e08,0x0f09
    //scan code of 'a-z 0-9'
}    ;
char str[22]="";
int *pstr=(int*)str;

struct {    
    char *name;
    int (*sum) () ;
    void (*show)();
    void (*change)(char *);
}    biosdesc[]={    
    "AMMMMI", write_amisum,show_ami_password, change_ami_password,
    "MR BIOS",write_mrsum,show_mrpassword,change_mrpassword,
    "DECpc",  NULL,show_dec_password,change_dec_password,
    "Phoenix",NULL,NULL,NULL,
}    ;

#define cprintf printf
void help(void)
{    
    cprintf("\nCMOS Password Utility (Version 1.00)         Mar 1996 Tel:(027)7800172\r\n");
    cprintf("(C) Copyright SunJian  CAD Center, HUST.           All Rights Reserved\r\n\n");
    cprintf("        Password utility for  AMI bios, MR bios & DECpc bios\r\n");
    cprintf("Usage : PWD                --display bios password directly\r\n");
    cprintf("        PWD [new_password] --change bios password\n");
    cprintf("\r\n");
    return;
}

int biostype=0;

/*main function of cmos*/
void main(int argc, char *argv[])
{    
    
    clrscr();
    help();
    
    biostype=test_biostype();
    if(biostype==0 )
    {        
        printf("Unknow BIOS!\n");
        return;
    }
    printf("BIOS type: %s\n",biosdesc[biostype-1].name );
    if (argc==2)
    {        
        if(biosdesc[biostype-1].change)
            (*biosdesc[biostype-1].change)(argv[1]);
    }
    else if (argc==1)
    {        
        if(biosdesc[biostype-1].show)
            (*biosdesc[biostype-1].show)();
    }
}

/* print CMOS element */
void display()
{    
    int i;
    
    for (i=0x0 ;i<0x10 ;i++)
        printf("%-5x",i);
    for (i=0x10 ;i<0x80 ;i++)
        printf("%-5x",rbyte(i));
    printf("\n");
}

BYTE rbyte(int port)
{    
    outp(INDEX,port);
    outp(0xed, port);
    return inp(VALUE);
}

void wbyte(int port, unsigned value)
{    
    disable();
    outp(INDEX,port);
    outp(0xed, port);
    outp(VALUE, value&0xff);
    enable();
}

void outw(int port, unsigned value)
{    
    wbyte(port, value&0xff);
    wbyte(port+1, value>>8);
}

WORD inw(int port)
{    
    WORD value;
    outp(INDEX,port);
    outp(0xed, port);
    value=inp(VALUE);
    
    outp(INDEX,port+1);
    outp(0xed, port+1);
    value= value+( inp(VALUE)<<8 );
    return value;
}

/*cal checksum of ami bios, From addr 34 to 3d and 40 to ...,save to 3e*/
int write_amisum()
{    
    WORD i=0,num;
    WORD sum=0;
    BYTE movsi[]={        
        0xbe,0x40,0xe0,0
    };
    //code of MOV si, e040
    BYTE far *pkey=(BYTE far*)movsi;
    WORD far *p;
    BYTE far *ROM=(BYTE far*)MK_FP(0xf000,0);
    
    for(i=0;i<0xa;i++)
        sum+=rbyte( 0x34+i);
    for (i=0;i<0xfff0;i++)
    if (_fstrncmp(ROM+i,pkey,3)==0)
        break;
    if (i<0xfff0)
    {        
        ROM+=i;
        p=(WORD far*)ROM+3;
        p=(WORD far*)MK_FP(0xf000, *p);
        num= *p;
        p=(WORD far*)ROM+5;
        num=num-  *p;
        for(i=0;i<num;i++)
            sum+=rbyte(0x40+i);
    }
    wbyte(0x3f, sum&0xff);
    wbyte(0x3e, sum>>8);
    return sum;
}

//calculate checksum of mrbios, part addr of 10 to 3e, save to 3f
int write_mrsum()
{    
    BYTE mask[6]={        
        0x7f,0xf8,0x3f,0xff,0xf8,0x0a
    }  ;
    BYTE v,cx;
    register unsigned char sum=0x1f;
    int i,addr;
    
    addr=0x10;
    for (i=5;i>=0;i--)
    {        
        v=mask[i];
        for (cx=0;cx<8;cx++)
        {            
            if (v&1)
                sum+= rbyte(addr);
            addr++;
            v >>=1;
        }
    }
    sum= sum&0x1f;
    wbyte(0x3f,sum);
    return sum;
}

/*calculate checksum , from addr 10 ot 2d */
void cal_checksum( int checklen)
{    
    WORD value, sum =0,i;
    
    for (i=0x10 ;i<checklen ;i++)
        sum+= rbyte(i);
    value=inw(0x3e);
    printf("\nSUM (2e)=%-5x (3e)=%-5x\n", sum,value);
    wbyte(checklen+1, sum&0xff);
    wbyte(checklen, sum>>8);
}

/*  Test your MotherBoard BIOS type */
int test_biostype(void)
{    
    char far  *ROM;
    WORD i,type;
    
    for(type=0 ;type<sizeof(biosdesc) / sizeof(biosdesc[0]);type++)
    for(i=0; i<0xfff0; i++)
    {        
        ROM=(char far *) MK_FP(0xf000,i);
        if(! _fstrncmp(ROM, biosdesc[type].name, 5))
            return type+1;
    }
    return 0;
}

/* Calc Security Code of special Password*/
WORD mr_Encrypt(int len)
{    
    //reference write cmos f000:ea16
    asm cld
    asm lea si,str
    asm mov cx,len
    asm mov dx,0xffff
    asm mov bx,0x1021
    l7200:
    asm lodsw
    asm  push cx
    asm  mov cl,0x10
    l7220:
    asm shl ax,1
    asm rcl dx,1
    asm jae next
    asm xor dx,bx
    next:
    asm loop l7220
    asm pop cx
    asm loop l7200
    return _DX;
    //C version
    /*
    WORD *p=(WORD*)str,ax,cf,df;
    BYTE cx;
    WORD dx=0xffff,bx=0x1021;
    while(*p)
    {        
        ax= *p++;
        for(cx=0;cx<0x10;cx++)
        {            
            cf= ax>>15;
            ax<<=1;
            df=dx&0x8000;
            dx=(dx<<1)+cf;
            if (df)
                dx^=bx;
        }
    }
    return  dx;
    */
}

/*Show Current MR BIOS Password String*/
void show_mrpassword()
{    
    WORD  code;
    register unsigned char i1,i2;
    char i3,i4, tt ,i5=0;
    int count=0;
    int dest;
    char *check[4]={        
        "Disable","Setup only",
        "Powerup & Setup","Bootup & Setup"
    };
    
    // 3a 3b  is security code
    dest=inw(0x3a);
    code=rbyte(0x3c)>>6;
    printf("Security Code=0x%04X %s\n",dest, check[code]);
    printf("         Press Esc to quit\n");
    
    //if no password found , use followed line and run again
    //    for (i5=0 ;i5<=26,count==0 ;i5++)
    {        
        *(pstr+4)=scan_code[i5];
        for (i4=0 ;i4<=26 ;i4++)
        {            
            
            *(pstr+3)=scan_code[i4];
            if( i4==0 && i5)
                continue;
            for (i3=0 ;i3<=26 ;i3++)
            {                
                *(pstr+2)=scan_code[i3];
                if( i3==0 && i4) continue;
                for (i2=0 ;i2<=26 ;i2++)
                {                    
                    *(pstr+1)=scan_code[i2];
                    if( i2==0 && i3) continue;
                    for (i1=1 ;i1<=26 ;i1++)
                    {                        
                        *pstr=scan_code[i1];
                        tt=5;
                        if (i5==0) tt=4;
                        if (i4==0) tt=3;
                        if (i3==0) tt=2;
                        if (i2==0) tt=1;
                            
                        code=mr_Encrypt(tt);
                        if(code==dest)
                        {                            
                            count++;
                            printf("Password=");
                            printf("%c%c%c%c%c\n",str[0],str[2],
                            str[4],str[6],str[8]);
                        }
                        if( bioskey(1) && (getch()==27))  return;
                        }
                }
            }
        }
    }
    printf("Total %d  password\n",count);
}

/* Extend the KEY's scan code */
void mr_ascii2scan_code()
{    
    int num, i;
    
    num=strlen(str);
    for (i=num-1; i>=0; i--)
        str[i]=tolower( str[i]);
    for (i=num-1; i>=0; i--)
    if( str[i]<='9')
        *(int*)(str+2*i)=scan_code[str[i]-'0'+26];
    else
        *(int*)(str+2*i)=scan_code[str[i]-'a'+1];
    *(str+2*num)=0;
}

//change password for mr bios
void change_mrpassword(char *pass)
{    
    int code;
    
    printf("NewPassword=%s\n",pass);
    strcpy(str,pass);
    mr_ascii2scan_code();
    code=mr_Encrypt(strlen(str)/2);
    printf("Security Code=0x%04X\n", code);
    // 3a 3b  save security code
    outw(0x3a,code);
    // calculate check sum 2e & 3f
    write_mrsum();
    return;
}

//get scancode of password for DECpc
//addr 58-5E save password
void dec_unEncrypt(char *pass)
{    
    int crc=0;
    BYTE cx,c;
    
    for ( cx=0;cx<7;cx++)
    {        
        c=rbyte(0x58+cx);
        _CL=7-cx;
        _AL=c;
        asm rol al,cl
        c= _AL;
        c ^=0xaa;
        crc=crc+c;
        pass[cx]=c;
        if (c==0) break;
        }
    if (crc != rbyte(0x5f))
        printf("password CRC error \n");
}

//change password for DECpc
void change_dec_password(char *pass)
{    
    int crc=0,cx;
    BYTE c,i,*p;
    
    printf("NewPassword=%s\n",pass);
    p=(BYTE*)scan_code;
    //translate form ascii to scancode
    for  ( cx=0;cx<7;cx++)
    {        
        c=tolower(pass[cx]);
        for (i=1;i<=36;i++)
        if(c==p[i*2])
            break;
        if(i<=36)
            pass[cx]=p[i*2+1];
        else
            pass[cx]=0;
    }
    for ( cx=0;cx<7;cx++)
    {        
        c=pass[cx];
        crc=crc+c;
        c ^=0xaa;
        _CL=7-cx;
        _AL=c;
        asm ror al,cl
        c=_AL;
        wbyte(0x58+cx,c);
        if (pass[cx]==0)
            break;
    }
    wbyte(0x5f, crc );
    return;
}

/*  Show Current DECpc  Password String  */
void show_dec_password()
{    
    BYTE ch,*p=(char*)scan_code;
    BYTE *pstr=str;
    int i, maxc= 36;
    
    str[7]=0;
    dec_unEncrypt( str);
    //translate from scancode to ascii
    while((ch= *pstr)!=0)
    {        
        for (i=1;i<=maxc;i++)
        if(ch==p[i*2+1])
            break;
        *pstr= p[i*2];
        pstr++;
    }
    printf("Password=%s\n",str);
    return ;
}


char AMI_unEncrypt( char c1,char c2)
{    
    //C version of AMI_unEncrypt
    /*
    BYTE num[]={        
        0,1,1,2
    };
    int di=0,c;
    do{        
        c=num[key>>6]+num[key&3];
        if (c&1)
            key=0x80+(key>>1);
        else
            key>>=1;
        di++;
    }while(key!=c2);
    return di;         */
    asm xor di,di
    asm mov bl,c1
    asm mov cl,c2
    lab1:
    asm test bl,0xc3
    asm jpe lab2
    asm stc
    lab2:
    asm rcr  bl,1
    asm inc di
    asm cmp bl,cl
    asm jne lab1:
    return _DI;
}


unsigned char ami_Encrypt(BYTE t, BYTE key)
{    
    //C version of Encrypt
    /*
    BYTE num[]={        
        0,1,1,2
    };
    BYTE c;
    while(t--){        
        c=num[key>>6]+num[key&3];
        if (c&1)
            key=0x80+(key>>1);
        else
            key>>=1;
    }
    return key;*/
    asm mov  al,t
    asm mov bl,key
    mark1:
    asm  test bl,0xc3
    asm jpe mark2
    asm stc
    mark2:
    asm rcr bl,1
    asm dec al
    asm jnz mark1
    asm mov key,bl
    return key;
}

/*change password for ami bios*/
//0x38-3d password code  0x37 initial value
void change_ami_password(char *pass)
{    
    BYTE code[8];
    char *p=pass;
    int i=0;
    
    printf("NewPassword=%s\n",pass);
    code[0]= 0x80;
    while( *p && i++<6)
        code[i]=  ami_Encrypt( *p++,code[i-1]);
    if (i<6)
        code[++i]=0;
    do
    wbyte(0x37+i,code[i] );
    while(i-->=0);
        write_amisum();
}

/*  Show AMI Password String  */
void show_ami_password()
{    
    int  i, length;
    static BYTE secret[7];
  for(length=0; length<7; length++)
        secret[length] = rbyte(0x37+length);
    secret[0] &= 0xf0;
    for(i=0; i<7 ,secret[i+1]>0; i++)
        str[i] = AMI_unEncrypt(secret[i], secret[i+1]);
    str[i+1]=0;
    if (secret[1]==0)
        printf("No password\n");
    else
        printf("Password=%s\n",str);
}
 
-- 
                  jesse (捷思)
                   潇洒逛一回
※ 修改:.haojs 于 Sep  5 19:16:16 修改本文.[FROM: bbs.hit.edu.cn]
--
※ 转寄:.武汉白云黄鹤站 bbs.whnet.edu.cn.[FROM: bbs.hit.edu.cn]

--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: haojs.bbs@bbs.whnet.]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:209.557毫秒