|
恳请高手回答我的问题,请相信在此之前,我已在网上找了无数答案,苦想了许多天仍不能弄懂,怕以请高手们给详细地说说
这个你去查查“中断”和“标志寄存器” 调试时,程序把flag寄存器的 追踪标志TF(Trap Flag)置为1,CPU进入单步执行方式,即每执行一条指令,产生一个单步中断请求(1号中断) 产生该中断后,CPU自动将flag寄存器、CS、IP入栈(这个CS:IP指向被调试程序将要执行的指令),然后转到调试程序执行。 调试程序访问栈中保存的flag、CS、IP,就可以将被调试程序的CS、IP、flag显示出来。。。 除了单步调试外,程序还有一种断点调试。。。 断点就是将被调试程序的某处的指令临时储存起来,再更改为int3指令, 当程序执行到这里时,CPU将寄存器入栈,然后转到调试程序, 调试程序临时保存并显示寄存器值,然后还原被更改的指令,并且让用户输入一些命令,执行一些操作, 最后在将寄存器的值还原,再返回到断点的位置,使被调试程序继续执行下去。。。 ================================================= CPU怎么知道指令的长度~ 简单的说(不考虑前缀问题) CPU可以根据一条指令的第一个字节确定这个指令的长度~ 具体怎么实现,我不清楚,请为高人,猜想: 1.可能先取第一个字节,再根据第一个字节取剩下的字节 2.可能先取很多字节(因为指令有其最长长度),在根据第一个字节舍去剩下的字节(直接不使用)~ 3.其他可能也是有滴~~~ 求分~最近Kx有点紧张~~~ 还有,Windows是运行在保护模式下的,保护模式(x86的CPU)的中断机制与8086的不同。。。 所以我上面说的只是在8086中。。。 用Windows调试程序,实际情况有点复杂,但是大致是一样的...... |
|
int13绝对读磁盘出错(已解决,求原因~)
嘿嘿,解决了,不过不明所以~ 果然是栈的问题。。。 我程序一开始得栈设ss=0x9000,sp=0 后来改为ss=0x8000,sp=0 就可以了 bochs和virtual PC、真机,的不同结果应该是因为不同的BIOS程序~ 不过还是有点不解~ 0x90000-0x9FFFF这段内存BIOS应该是不使用的吧~ 为什么会有影响呢~ 求解释,分就给先让我明白真相的的人吧~ |
|
int13绝对读磁盘出错(已解决,求原因~)
这个非法命令,是BIOS程序的返回值~ |
|
[求助]在调试游戏时无法返回调试器
这个,我也遇到过 我猜,貌似是因为游戏的全屏退回到桌面是需要执行一些代码的~ 然后od把游戏暂停,游戏不能继续,而这段退回到桌面的代码也不能执行~ 我当时是开启 将记录自动存文件 的功能~ 游戏一停, 直接结束进程 然后再看记录文件~ 很麻烦~建议去找其它大神~ |
|
新手求教编码问题
借用百度百科: 指令是指示计算机执行某种操作的命令,它由一串二进制数码组成。 一条指令通常由两个部分组成:操作码 +地址码 。 操作码:指明该指令要完成的操作的类型或性质,如取数、做加法或输出数据等。 地址码:指明操作对象的内容或所在的存储单元地址。 自己写的: CPU内部有一种叫寄存器的东西,可以记录一些信息, 其中有两个寄存器叫CS和IP,他记录了当前执行的指令的位置~ CS:IP指示出内存中的一个位置 CPU从这个位置取一些二进制信息~,取的长度由取的信息决定 (这里听起来有点纠结,不过) 这一段取出的二进制信息就被CPU当做指令来执行 (其实不严谨的说,机器语言就是这些指令按一定顺序组合在一起) 有一部分指令,比如说一条访问内存的“mov ax,[bx]”指令 ax,bx是寄存器(记录了一些信息) 在执行这条指令时,bx里的二进制信息,会被看成是地址, 而在内存中,起始位置为bx,长度为2字节(两操作数长度一致,而ax是2字节的)的一段信息,就被看成是数据,被CPU读出,并用这个读出的值来改变ax的值 更特殊的,一段二进制信息可以被同时看做是数据和信息(这个只是说说,你还是先不要尝试去弄懂它,等到学好基础时再自己看书去~) 比如: jmp near Lable1 Lable1: mov ax,cs:[Lable1] 这里执行到第二条指令时,CS:[Lable1]和CS:IP指向内存的同一位置,这一位置的二进制信息既是数据又是指令 建议去了解一下“图灵机”和“存储程序原理”,你对计算机的一些基本概念看起来似乎不甚了解。。。 建议再次阅读王爽《汇编语言》的1-3章,看起来你是刚学编程的人,这3章最好看上3、4遍。而且,提醒(而不是建议)一下,学编程最好从高级语言入手,比如PASCAL,C也有必要了解,(不过C比较难上手) 有条件可以研究一下《深入理解计算机系统》的第一章和第四章(这本书好,虽然比较贵,而且有些地方需要一定数学基础,不过这些地方可以略过,不影响你对计算机的了解~) |
|
|
|
int13绝对读磁盘出错(已解决,求原因~)
我写的程序是一个在软盘里的引导扇区~ 也就是说,真机 其实是无操作系统的环境 ,这时我使用的是真实的软盘~ 不过我使用Virtual PC,不管是img镜像,还是真实的软盘,都会出现这个问题~ |
|
求段汇编概率代码
这段代码将测试一次概率y/x,结果保存在eax中 1. r=GetTickCount()(这个函数不懂?返回自windows启动以来的毫秒数) 2. b=r mod a,这样b/a是一个0至1的小数 3. 比较b/a和y/x,当b/a<=y/x时,返回eax=1,否则eax=0 对于第1步, 因为GetTickCount的值随机性不强,所以可以进行适当变换 1.1. r=GetTickCount() 1.2. r=各种变来变去(r) 对于第3步, 比较b/a和y/x,相当于比较b*x和y*a,所以第3步如下进行 3.1. m=b*x 3.2. n=y*a 3.3. eax=(m<=n)?1:0,在代码中,我将(m<=n)改为(n>=m)。 ================================================================ 1.1. 首先取得一个随机数r 00401020 >call kernel32.GetTickCount ; [GetTickCount 1.2. 然后对r进行一定变换,因为GetTickCount的结果是单调递增的,随机性不好 00401025 mov edx, eax ; 对r进行变换 00401027 rol eax, 1 00401029 xor eax, edx 0040102B rol eax, 3 0040102E xor eax, edx 00401030 rol eax, 7 00401033 xor eax, edx 00401035 rol eax, 15 00401038 xor eax, edx 2. b=r mod a,使用64位除法以防除法溢出 同时a为16位数,这样可以使b也为16位数 执行后a=ecx,b=ebx 0040103A mov ecx, 0D4DD ; a=0xD4DD,16位素数 0040103F xor edx, edx 00401041 div ecx ; b=r mod a 00401043 mov eax, edx 3.1. m=b*x,x为16位数,b也为16位数,结果为32位数,正好存在eax中 执行后m=ebx 00401045 mov edx, 64 ; x=0x64=100,16位整数 0040104A mul edx ; m=b*x 0040104C mov ebx, eax 3.2. n=y*a,y为16位数,a也为16位数,结果为32位数,正好存在eax中 执行后n=eax 0040104E mov eax, ecx ; eax=a 00401050 mov edx, 32 ; y=0x32=50,16位整数 00401055 mul edx ; n=a*y 3.3. 比较n和m,当n>=m时,eax=1,否则eax=0。 00401057 cmp eax, ebx 00401059 mov ecx, 0 0040105E mov edx, 1 00401063 cmovge ecx, edx 00401066 mov eax, ecx ; eax=(n>=m)?1:0 呃,补充一下, 如果要写成函数,那个x和y要改成函数的参数, 比如mov edx, 64 可能改为mov edx,[ebp-8]之类的~ 再补充一下, 这个GetTickCount的精度是1毫秒, 所以如果你要非常频繁的调用这个函数 那么你还是用其他方法得到r比较好 |
|
求段汇编概率代码
你的意思是说, 你已经获得了一个随机数x(0<=x<=max),还有一个概率y%, 现在要进行一次随机? 汇编我不会,不过伪代码如下: if(x/max*100<=y) then return true else return false; 比如x=100(0<=x<=256,max=256),y%=50%,也就是y=50 那么判断 100/256*100与50的大小关系~ |
|
|
|
[求助]诡异的程序
正解,.net程序要用专门的工具调试,用od是不行滴~(当然,这个不是绝对的,高手应该可以吧~) |
|
:eek:请老师们看看一下这样.Net程序能不能爆破 (附有il代码)
“L_01b5: brfalse.s L_0201”改为“brfalse.s L_01b7”试试 我只是对IL稍微有些了解~有可能是错的~ 理由如下: L_01a9: ldloc.s V_4;载入V_4 L_01ab: ldstr "验证通过,欢迎使用本软件。"/;载入这个字符串 L_01b0: call bool string::op_Equality(string, string);比较 L_01b5: brfalse.s L_0201;不匹配就跳(关键跳~) ……省略~ L_01c3: ldstr "已注册为商业版";验证成功的提示信息 L_0201: ldloc.s V_4 L_0203: ldstr "验证失败,请购买正版软件。";验证失败的提示信息 |
|
Descriptor是什么指令
Descriptor 是一个叫“段描述符”的 数据结构,用来指定线性地址中的一段内存 如果你是在看《一个操作系统的实现》或者是《自己动手写操作系统的话》 这个数据结构定义在"pm.inc"文件内: ; usage: Descriptor Base, Limit, Attr ; Base: dd ; Limit: dd (low 20 bits available) ; Attr: dw (lower 4 bits of higher byte are always 0) %macro Descriptor 3 dw %2 & 0FFFFh ; 段界限1 dw %1 & 0FFFFh ; 段基址1 db (%1 >> 16) & 0FFh ; 段基址2 dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 属性1 + 段界限2 + 属性2 db (%1 >> 24) & 0FFh ; 段基址3 %endmacro ; 共 8 字节 |
|
|
|
|
|
一个C问题
注:我使用的不是VC6.0,而是TC2.0,所以有一些地方可能会与你不同。 注:由于写的比较仓促,有可能有错,也有可能不好懂,将就一下吧。。。 =================浮点数相关知识=================(如果你认为你懂可以略过) 以下是有关浮点数的解释(如果你找我要资料的话我只能说是来自《深入理解计算机系统》一书) 【Part1.有关IEEE浮点数的规定】 所谓浮点数,顾名思义,就是小数点会浮动的数(有别于定点数) 浮点数是一种表示实数的方法,它将一个实数V解释为:V=2^X * Y,其中X和Y都为整数 现在的浮点数都是使用IEEE浮点数表示法(IEEE浮点表示法准确来说是一种规范,是人为规定的), 每一个IEEE浮点数表示为:符号域|指数域|小数域,或说是:s|e|m,这里s,e都是二进制整数串,(0≤m<1)m是个二进制纯小数串。 IEEE浮点数有三种: 单精度浮点数(float): 符号域1位,指数域8位,小数域23位,共32位,Bias=2^(8-1) -1=127 双精度浮点数(double): 符号域1位,指数域11位,小数域52位,共64位,Bias=2^(11-1) -1=1023 扩展精度浮点数(c语言似乎不支持): 符号域1位,指数域15位,整数域1位,小数域63位,共80位(它比较特殊,这里不讨论) 注:Bias,Biased的缩写,中文翻译:偏置 IEEE浮点数的值分三种情况:规格化值,非规格化值,特殊数值 规格化值(用于表示绝对值较大的数字): 当指数域不全为0且不全为1时,该IEEE浮点数为规格化值。 此时E=e-Bias,M=1+m…,S=s V=(-1)^S * M * 2^E 非规格化值(用于表示绝对值较小的数字如0): 当指数域全为0时,该IEEE浮点数为非规格化值。 此时E=1-Bias,M=0+m…,S=s V=(-1)^S * M * 2^E 特殊数值(用于表示正无穷、负无穷、以及"不是一个数"): 当指数域全为1时,该IEEE浮点数为特殊数值。 若小数域全为0且s=0时V=+∞ 若小数域全为0且s=1时V=-∞ 若小数域不全为0时,V=NaN(Not a Number,不是一个数),比如虚数就是用NaN表示 【Part2.例子】 结合例子,比较容易理解【Part1】 float小数:1|01111110|10000000000000000000000 符号域:1 指数域:01111110,规格化值 小数域:10000000000000000000000 s=1 e=1 m=0.10000000000000000000000(2) S=s=1 E=e-Bias=126-127=-1 M=1+m=1+0.1(2)=1.1(2)=1.5 V=-1.5 * 2^-1=-0.75 float小数:0|00000000|11111111111111111111111 符号域:0 指数域:00000000,非规格化值 小数域:11111111111111111111111 s=0 e=0 m=0.11111111111111111111111(2) S=s=1 E=1-Bias=1-127=-126 M=0+m=0+0.1(2)=0.1(2)=0.5 V=0.5 * 2^-126=2^-127 double小数:0|11111111111|000000…… 符号域:0 指数域:11111111111,特殊的值 小数域:000000…… V=+∞ ================引入=================== 写个c语言的程序: #include <stdio.h> int main(){ float x=1; double y=1; printf("%u %u %u %u\n",(float) x); printf("%u %u %u %u\n",(double) x); printf("%u %u %u %u\n",(float) y); printf("%u %u %u %u\n",(double) y); return 0; } 程序输出: 0 0 0 16368 0 0 0 16368 0 0 0 16368 0 0 0 16368 ============反汇编代码分析============= IDA反汇编: seg000:01FA ; int __cdecl main(int argc,const char **argv,const char *envp) seg000:01FA _main proc near ; CODE XREF: start+11Ap seg000:01FA seg000:01FA var_14 = qword ptr -14h seg000:01FA var_C = dword ptr -0Ch seg000:01FA var_8 = word ptr -8 seg000:01FA var_6 = word ptr -6 seg000:01FA var_4 = word ptr -4 seg000:01FA var_2 = word ptr -2 seg000:01FA argc = word ptr 4 seg000:01FA argv = dword ptr 6 seg000:01FA envp = dword ptr 0Ah seg000:01FA seg000:01FA push bp seg000:01FB mov bp, sp seg000:01FD sub sp, 0Ch 以上是变量定义,以及函数初始化。 注意一下var_14=-14h,sp=bp-0Ch,后面有用。 seg000:0200 mov dx, 3F80h ; <suspicious> seg000:0203 xor ax, ax seg000:0205 mov word ptr [bp+var_C+2], dx seg000:0208 mov word ptr [bp+var_C], ax 这是赋值语句“x=1”,dword var_C其实就是x,赋值后 x=0|01111111|00000000000000000000000 指数域为01111111,为规格化值, e=127,E=0, m=00000000000000000000000, M=1.00000000000000000000000, s=S=0, V=(-1)^S * M * E=1.0 seg000:020B mov [bp+var_2], 3FF0h ; <suspicious> seg000:0210 mov [bp+var_4], 0 seg000:0215 mov [bp+var_6], 0 seg000:021A mov [bp+var_8], 0 这是赋值语句 “y=1”,qword var_2其实就是y,赋值后y=0|011111111111|000000000000000000000000000000000000000000000000000 指数域为011111111111,为规格化值, e=1023,E=0, m=000000000000000000000000000000000000000000000000000, M=1.000000000000000000000000000000000000000000000000000, s=S=0, V=(-1)^S * M * E=1.0 seg000:021F fld [bp+var_C] ; (emulator call) seg000:0223 sub sp, 8 seg000:0226 fstp [bp+var_14] ; (emulator call) seg000:022A wait ; (emulator call) seg000:022C mov ax, 194h ; <suspicious> seg000:022F push ax ; format seg000:0230 call _printf seg000:0230 seg000:0233 add sp, 0Ah 这里先将float类型的var_C转换为double类型,再调用printf函数(后面的add是堆栈平衡) 其实此时 sp=bp-0Ch-8h=bp-14h,而bp+var_14=bp-14h,所以[bp+var_14]=[sp]。 可以看出var_C转换后直接入栈了。 这就是第一个printf函数:printf("%u %u %u %u\n",(float) x); 注:有关浮点指令请另查资料,我也不是很懂。 seg000:0236 fld [bp+var_C] ; (emulator call) seg000:023A sub sp, 8 seg000:023D fstp [bp+var_14] ; (emulator call) seg000:0241 wait ; (emulator call) seg000:0243 mov ax, 1A1h ; <suspicious> seg000:0246 push ax ; format seg000:0247 call _printf seg000:0247 seg000:024A add sp, 0Ah 第二个printf,跟第一个的差别仅在于格式字符串的地址不同,从而印证了我的猜想:float在printf时被隐式的转换成了double。 下面的反汇编代码分析可以略过。 seg000:024D fld qword ptr [bp+var_8] ; (emulator call) seg000:0251 sub sp, 8 seg000:0254 fstp [bp+var_14] ; (emulator call) seg000:0258 wait ; (emulator call) seg000:025A mov ax, 1AEh ; <suspicious> seg000:025D push ax ; format seg000:025E call _printf seg000:025E seg000:0261 add sp, 0Ah 第三个printf,跟前两个相差无几,不过fld指令的参数不是x而是y。 seg000:0264 push [bp+var_2] seg000:0267 push [bp+var_4] seg000:026A push [bp+var_6] seg000:026D push [bp+var_8] seg000:0270 mov ax, 1BBh ; <suspicious> seg000:0273 push ax ; format seg000:0274 call _printf seg000:0274 seg000:0277 add sp, 0Ah 第四个printf,不需要类型转换,直接push。 seg000:027A xor ax, ax seg000:027C jmp short $+2 seg000:027E mov sp, bp seg000:0280 pop bp seg000:0281 retn seg000:0281 seg000:0281 _main endp 重置bp,返回0于ax中。 至此代码分析完成。 ===============分析第四个printf================= 下面分析第四个printf,以说明“0 0 0 16368”这样的输出时怎样产生的。 (首先请确保你已经对IEEE浮点数有所了解) “double y=1;”,赋值后 y=0|011111111111|000000000000000000000000000000000000000000000000000=1.0 seg000:0264 push [bp+var_2] seg000:0267 push [bp+var_4] seg000:026A push [bp+var_6] seg000:026D push [bp+var_8] 这里是将double类型的y入栈,但是我们也可以看做是将4个unsigned类型的整数入栈: 0011111111111000,0000000000000000,0000000000000000,0000000000000000 就是16368,0,0,0 然后printf就将他们输出:0 0 0 16368 ===============总结================== 在你的程序中:printf("%d",c); 输出0的原因如下: 1.float类型被强制转换为double 2.转换后double类型的低16位为0 3."%d"只输出了double类型的低16位 ===================================== 还有不明白,可以自己查资料,也可以加QQ1025266550问我,注明来自PEDIY谢谢。 |
|
一个C问题
似乎跟printf函数有关系,我 printf("%d",1.1e5); 还是输出0 不知道跟你的编译器是否一致(无VC6,压力大) 在我的电脑上, printf("%u %u %u %u\n",(float) x); printf("%u %u %u %u\n",(double) x); 的输出保持一致,看上去float被强制转换成了double. |
操作理由
RANk
{{ user_info.golds == '' ? 0 : user_info.golds }}
雪币
{{ experience }}
课程经验
{{ score }}
学习收益
{{study_duration_fmt}}
学习时长
基本信息
荣誉称号:
{{ honorary_title }}
能力排名:
No.{{ rank_num }}
等 级:
LV{{ rank_lv-100 }}
活跃值:
在线值:
浏览人数:{{ visits }}
最近活跃:{{ last_active_time }}
注册时间:{{ user_info.create_date_jsonfmt }}
勋章
兑换勋章
证书
证书查询 >
能力值