首页
社区
课程
招聘
探秘INT3指令
发表于: 2020-6-7 10:54 6640

探秘INT3指令

2020-6-7 10:54
6640

此贴涉及到一些错误,,请求删帖。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2020-6-9 11:03 被码小芹编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (30)
雪    币: 688
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
我来纠正一下,楼主这种解释是歪解了:
"原因是产生异常后系统调用了nt!KiTrap03( )时令eip - 1"
无论是LONG INT3 还是 INT3指令,触发后系统是绝对不会修改EIP的,
其实所有的异常触发之后,系统都不会修改EIP,这个是原则问题,
就是保留现场的意思.而将EIP减去1的这个操作,是调试器做的,
这样解释,刚好也符合了你后面所说的:LONG INT3在触发后,EIP停留在异常位置+1的地方,为什么会这样傻?
其实这个是OD的BUG,OD作者开发的时候,应该是没有考虑到LONG INT3的处理,一切触发INT3的异常,就无脑将EIP-1,
所以出现了楼主所说的情况,(INT3无脑-1=异常位置),而(LONG INT3无脑-1 = 异常位置+1)
如果不是无脑-1的话,那么触发LONG INT3应该是-2,而EIP应该是停留在ExceptionAddress处.
OD笑话不少,人品差的人怎么可能做得出好的软件.
2020-6-7 16:29
1
雪    币: 126
活跃值: (759)
能力值: ( LV3,RANK:21 )
在线值:
发帖
回帖
粉丝
3
flarejune 我来纠正一下,楼主这种解释是歪解了: "原因是产生异常后系统调用了nt!KiTrap03( )时令eip - 1" 无论是LONG INT3 还是 INT3指令,触发后系统是绝 ...

.text:00436CEF loc_436CEF:                 
.text:00436CEF                               ; _KiTrap03+D6j
.text:00436CEF mov     esi, ecx             
.text:00436CF1 mov     edi, edx
.text:00436CF3 mov     edx, eax
.text:00436CF5 mov     ebx, [ebp+68h]       
.text:00436CF8 dec     ebx                   ; eip-1
.text:00436CF9 mov     ecx,                 
.text:00436CFE mov     eax, 80000003h        ; 异常类型
.text:00436D03 call    CommonDispatchException ; 处理异常

这是KiTrap03的部分代码,确实是使eip - 1。您说的那个原则问题,可能是你只认为中断机制就是保留现场,恢复现场。
但是int3指令本来就使0x86cpu用来支持调试的一条指令,他确实比较特殊。
如果您有什么问题可以用windbg自己去查看一下KiTrap03函数的汇编代码。
多谢回复。

最后于 2020-6-7 17:21 被码小芹编辑 ,原因:
2020-6-7 17:20
0
雪    币: 688
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4


看你EIP前EIP后的,估计可能还是个XP系统,好吧,其它我姑且不理,以上这个图,是在WIN10下运行的,这个是我在调试"调试器"时候的截图,触发INT3异常时候,IP是790,而不是78F.

你上面说的减一,我是打死不相信微软这样做的,如果这样做的话,微软可以去死了.真的.

如果你还不服气,你自己跑一个DEMO吧,不是IP不变的话,你回来通知我吃屎好吧.

static LONG CALLBACK VectoredHandler(
	_In_ PEXCEPTION_POINTERS ExceptionInfo
)
{
	if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
	{
		//Increase EIP/RIP to continue execution.
#ifdef _WIN64
		ExceptionInfo->ContextRecord->Rip++;
#else
		ExceptionInfo->ContextRecord->Eip++;
#endif
		return EXCEPTION_CONTINUE_EXECUTION;
	}
	return EXCEPTION_CONTINUE_SEARCH;
}



void Interrupt_3()
{
	PVOID Handle = AddVectoredExceptionHandler(1, VectoredHandler);
	__debugbreak();
	RemoveVectoredExceptionHandler(Handle);
}

你调用Interrupt_3函数,在自定义异常处理里面,++是跳过这个INT3指令,如果按你所说的话,那么不应该是++跳过,而是+=2跳过.你思维还跟不上的话,我懒得和你扯了.

最后于 2020-6-7 17:56 被flarejune编辑 ,原因: 修正错别字
2020-6-7 17:55
0
雪    币: 126
活跃值: (759)
能力值: ( LV3,RANK:21 )
在线值:
发帖
回帖
粉丝
5


最后于 2020-6-7 18:21 被码小芹编辑 ,原因:
2020-6-7 18:06
0
雪    币: 688
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
码小芹
你不是献丑,你是误人子弟罢了.
减一操作是不是调试器做的,你看不了OD的代码,你可以看下X64DBG TITANENGINE的代码:
https://github.com/x64dbg/TitanEngine/blob/51ba022c29d3faae424ac6c51c0d7fb0a4cb5b84/TitanEngine/TitanEngine.Debugger.DebugLoop.cpp#L472
你只是静态看了这个汇编指令,你都没有跑过,你怎么知道系统有执行过那段指令?
实践出真理,不要死读书诗,尽信书不如无书.
2020-6-7 18:22
0
雪    币: 126
活跃值: (759)
能力值: ( LV3,RANK:21 )
在线值:
发帖
回帖
粉丝
7
flarejune 你不是献丑,你是误人子弟罢了. 减一操作是不是调试器做的,你看不了OD的代码,你可以看下X64DBG TITANENGINE的代码: https://github.com/x64dbg/Titan ...
多谢大师的教诲
2020-6-7 18:29
0
雪    币: 12502
活跃值: (3053)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
学到了,大佬厉害厉害
2020-6-8 07:37
0
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
系统不会减1,减1需要调试器自行处理。int3 和int 3都会使指令实际位置在eip+1(被替换得那个指令位置+1).硬件执行断点可以准确得断在eip位置,不需要调试器修正eip
2020-6-8 08:16
0
雪    币: 126
活跃值: (759)
能力值: ( LV3,RANK:21 )
在线值:
发帖
回帖
粉丝
10
zylyy 系统不会减1,减1需要调试器自行处理。int3 和int 3都会使指令实际位置在eip+1(被替换得那个指令位置+1).硬件执行断点可以准确得断在eip位置,不需要调试器修正eip
哥呀,你再仔细读读我写的文章
2020-6-8 08:38
0
雪    币: 688
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11

看雪已经沦为52POJIE之类的FW场所了,
通过修改文章来掩饰自己的错误,然后反驳别人说别人诬陷它.
和之前某人做假图的方式一样,废物为了面子,啥都做了.
**************************

最后于 2020-6-8 22:20 被kanxue编辑 ,原因: 就事论事,以理服人!请注意语气,勿让他人感到不适
2020-6-8 12:23
1
雪    币: 688
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
"所以当cpu执行到此断点时就会执行0xCC(即INT3指令),接着产生异常去执行函数nt!KiTrap03(%20),此函数会将指令指针(eip)的值减一,因为其刚执行完0xCC此时eip指向0xCC的下一个字节,所以减一后eip重新指向0xCC(断点处)。接着会调用nt!KiDisPatchException( )函数并将异常分发给调试器"
这个是原话,关键点:触发INT(0XCC)后,nt!KiTrap先将EIP减一,再调用KiDisPatchException( )函数将异常分发给调试器.
到后面就改文章解释为:"此异常是第二次分发异常的时候使eip-1",其实傻屌依然是犯错,因为一旦触发异常,如果调试器不接手的话,直接抛出到SEH,SEH不接手就直接程序崩溃了,有它妹的第一第二次....再而且,如果将EIP-1的话,调试器不处理而直接NTContinune的话,那么就会无限循环了,一直卡在这个INT3这里,
而原文中后面对LONG INT3异常为什么依然EIP-1而不是EIP-2的描述,已经偷偷删除,因为那个是解释不过去了.
幸亏你小学的时候不是文科代表,要不然还真的中你道道了,玩文字游戏么?
2020-6-8 12:59
0
雪    币: 126
活跃值: (759)
能力值: ( LV3,RANK:21 )
在线值:
发帖
回帖
粉丝
13
flarejune "所以当cpu执行到此断点时就会执行0xCC(即INT3指令),接着产生异常去执行函数nt!KiTrap03(%20),此函数会将指令指针(eip)的值减一,因为其刚执行完0xCC此时eip ...
你看,急眼了急眼了
2020-6-8 13:18
0
雪    币: 688
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
高深的东西你是肯定不懂的了,我来告诉你nt!KiTrap里面那个减一是什么东西吧.
nt!KiTrap里面减一的那个并非是"真正的EIP",真正的EIP是在TEB里面的,nt!KiTrap修改的那个是准备传递给SEH或者VEH的参数
PEXCEPTION_POINTERS -> ExceptionRecord->Eip的值,如果有设置SEH处理或者VEH处理的话,比如我3楼那个例子,
那么在这里访问到的PEXCEPTION_POINTERS -> ExceptionRecord->Eip的值,就是真实Eip-1的值.你可以查看PEXCEPTION_POINTERS->ExceptionRecord的结构,数下Eip这个成员所在的偏移是不是0x68,也就是你所说的:
.text:00436CF5 mov     ebx, [ebp+68h]       
.text:00436CF8 dec     ebx                   ; eip-1
到现在为止,你该死而瞑目了吧.
好了,还要说一句:别叫我大佬,叫我伯伯,我做大佬的时候你还在穿开裆裤,你现在还叫我大佬?
2020-6-8 13:26
0
雪    币: 126
活跃值: (759)
能力值: ( LV3,RANK:21 )
在线值:
发帖
回帖
粉丝
15
flarejune 高深的东西你是肯定不懂的了,我来告诉你nt!KiTrap里面那个减一是什么东西吧. nt!KiTrap里面减一的那个并非是"真正的EIP",真正的EIP是在TEB里面的,nt!K ...
我现在是真心请教你,我们本来就是新手。
你上来就那种语气,我是真的受不了。
我就是请教你一下,那个od忽略异常的意思不就是异常交给程序和系统处理吗,那为什么程序没有处理,但是其eip却依然减一了呢 ?(我的意思也是此时调试器也没有处理啊)
我这是真心请教你,你能不能好好说话。当然要觉得我这种新手不配进入这个圈那就算了,耽误你时间了。
2020-6-8 13:35
0
雪    币: 5734
活跃值: (1737)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
16
不要吵了以我为准 系统减 1 (0xcc) 的操作在 KiDispatchException 头部 if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)  系统int3执行流程是 中断硬件程序 -> KiDebugTrapOrFault(r0) -> KiExceptionDispatch(r0) -> KiDispatchException(r0)->r3
2020-6-8 13:43
0
雪    币: 688
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
码小芹 我现在是真心请教你,我们本来就是新手。 你上来就那种语气,我是真的受不了。 我就是请教你一下,那个od忽略异常的意思不就是异常交给程序和系统处理吗,那为什么程序没有处理,但是其eip却依然减一了呢 ...
我不是这个圈那个圈的,我也很少来看雪,不过我注册看雪的帐号好像也有些年份了吧,
首先来说,我不是做逆向的,我是一个23年开发经验的开发者,我的逆向知识,也是前几年才随便看看的.
最近在开发调试器和做反反调试处理,所以去各大论坛看下收集下民意,如果有历史记录可以看的话,
你应该也就是发现我最近才活跃.
我说话语气就是那样的,我就是你们口中所说的那种少年得志的人,所以从小到大我都是那种语气说话.
回答你上面的问题,
正常来说,调试器是将非自己设置的INT3才当作是"异常",而忽略异常不处理的话,这里的异常就肯定是指那些非调试器自己设定的INT3.
那么问题来了,为什么时候会触发非调试器自己的INT3呢?莫非就是2个,1.程序跑飞了,2.被调试的程序自己做的int3(通常是反调试才会这样做).
而你说的那个情况,应该是第2条,正如我上面说的,触发异常后,系统调用SEH/VEH询问该如何处理,如果程序自身有做了SEH/VEH的话,就会在异常处理
函数里面对异常进行处理,而在调用SEH/VEH的时候,其参数PEXCEPTION_POINTERS->ExceptionRecord->Eip已经被减少1,用户处理完异常后,
必须会调用NTCONTINUE继续执行程序,那么系统就会将参数里面的Context写会到真实的ThreadContext里面去,所以,你什么都不做的话,其实经过这番操作后,EIP其实已经是减1了.
话又反过来说,就是因为刻意操作才会有INT3的产生,所以按实际情况的话,在VEH/SEH里面,用户是必定会对EIP进行处理的,就好像我4楼那个例子一样.
如果用户不处理的话,就会出现死循环,程序立马卡死无响应.
2020-6-8 13:53
0
雪    币: 126
活跃值: (759)
能力值: ( LV3,RANK:21 )
在线值:
发帖
回帖
粉丝
18
flarejune 我不是这个圈那个圈的,我也很少来看雪,不过我注册看雪的帐号好像也有些年份了吧, 首先来说,我不是做逆向的,我是一个23年开发经验的开发者,我的逆向知识,也是前几年才随便看看的. 最近在开发调试器和 ...
谢谢你的回复,我自己去写个简单的调试器验证一下。
2020-6-8 14:03
0
雪    币: 126
活跃值: (759)
能力值: ( LV3,RANK:21 )
在线值:
发帖
回帖
粉丝
19
#include <Windows.h>
#include <iostream>
using namespace std;
int flag = 0;                        //标志
int main()
{
    char a[256] = {0};
    cout<<"请输入需要调试的目标程序的路径:";
    cin>>a;
    PROCESS_INFORMATION pi;            //接受新进程的一些有关信息
    STARTUPINFO si;                    //指定新进程的主窗体如何显示
    DEBUG_EVENT devent;                //消息事件
    CONTEXT        stContext;            //线程信息块

    GetStartupInfo(&si);

    CreateProcessA(
         a,     
         NULL,  
         NULL,  
         NULL,  
         FALSE, // 不可继承
         DEBUG_ONLY_THIS_PROCESS | DEBUG_PROCESS, // 调试模式启动            (DEBUG_ONLY_THIS_PROCESS标志表示其不能调试进程如果被调试的话,此新进程不会成为其调试进程的调试对象)
         NULL,  
         NULL,
         &si,
         &pi ); 
    cout<<"创建进程成功"<<endl;

    while(TRUE)
    {
        if(WaitForDebugEvent(&devent, INFINITE))
        {
            switch(devent.dwDebugEventCode)
            {
            case EXCEPTION_DEBUG_EVENT:
                switch(devent.u.Exception.ExceptionRecord.ExceptionCode)
                {
                case EXCEPTION_BREAKPOINT:                //断点异常
                    
                    if(devent.u.Exception.dwFirstChance == 1)       //第一次异常分发
                    {
                        cout<<"第一次异常。  ";
                        cout<<"eip:";
                        stContext.ContextFlags = CONTEXT_FULL;
                        GetThreadContext(pi.hThread, &stContext);
                        int n1 = GetLastError();
                        cout<<stContext.Eip<<endl;
                        flag = 1;
                    }
                    if(devent.u.Exception.dwFirstChance == 0)        //第二次异常分发
                    {
                        cout<<"第二次异常。  ";
                        cout<<"eip:";
                        GetThreadContext(pi.hThread, &stContext);
                        cout<<stContext.Eip<<endl;
                        flag = 0;
                    }
                    break;
                }
                break;
            }

        }
        if(flag == 1)                        //如果是第一次碰见int3断点异常,我们不处理他,让他直接继续进行第二次异常分发
            ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
        else                                //如果是第二次碰见int3断点异常或者是其他调试事件我们直接返回让程序继续运行
        {
            flag = 0;
            ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId, DBG_CONTINUE);
        }
    }
    return 0;
}


就此结束把,我要去准备期末考试了。

要不就得挂科了

2020-6-8 17:24
0
雪    币: 688
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
码小芹 #include&nbsp;&lt;Windows.h&gt; #include&nbsp;&lt;iostream&gt; using&n ...

你这不是变着花样****?现在的年轻人,就是喜欢被***是吧?
我来和你说,你这个被调试的CmdLine1.exe的代码里面,是加了SEH或者VEH的,
你这个程序的执行过程如下:


执行遇到INT3指令->系统进入异常分发处理->检测有调试器否,有则直接提交给调试器(此时真实EIP没变)->现有调试器进行处理,如果调试器
ContinueDebugEvent(DBG_EXCEPTION_NOT_HANDLED)->系统准备SEH/VEH处理分发->将准备的参数PEXCEPTION_POINTERS -> ExceptionRecord->Eip减一后调用到SEH/VEH处理函数
->SEH/VEH处理函数处理完毕->调用NTContinue继续执行->NtContinue里将PEXCEPTION_POINTERS -> ExceptionRecord写回到线程上下文(这里注意里,由于刚才调用SEH/VEH函数
之前,已经将PEXCEPTION_POINTERS -> ExceptionRecord->Eip减了1,此时直接写回去的话,真实的EIP就变成了异常地址-1)->程序继续执行,但是由于当前EIP下面的还是那个INT3断点,
所以再次触发异常->系统再次进入处理者分发处理环节(Exception.dwFirstChance从1变为0,也就是你说的第二次...)

以上说的这个和我17楼说的内容一致.你的解释也没有为你说清楚系统修改了EIP这个情况.而实际上,系统根本没有修改过你的EIP(你还看不懂这句的话,你仔细琢磨下,关键问题是在那个NtContinue里面).
如果你那个CmdLine1.exe没有加入SEH/VEH处理的话,你在第一次异常调用ContinueDebugEvent(DBG_EXCEPTION_NOT_HANDLED)后,程序是直接崩溃了的,没有后文的了.
我不知道你是真傻还是假傻,将这个细节的东西隐藏了,然后发半个测试结果上来.和做假图的那些人没区别,人品差到极致,建议别继续学下去了,侮辱业界.

PS:题外话,你以上这个调试器的代码逻辑有问题,你那个PI的变量是你主线程,而你在调试器处理环节里面,你应该使用devent.dwThreadId来获取当前异常的线程,而不是抓住主线程来X.
而由于你测试的程序刚好是单线程的,所以你这样搞也没有发现问题.

最后于 2020-6-8 22:18 被kanxue编辑 ,原因: 就事论事,以理服人!请注意语气,勿让他人感到不适
2020-6-8 19:23
0
雪    币: 126
活跃值: (759)
能力值: ( LV3,RANK:21 )
在线值:
发帖
回帖
粉丝
21
flarejune 你这不是变着花样找脸抽么?现在的年轻人,就是喜欢被抽脸是吧? 我来和你说,你这个被调试的CmdLine1.exe的代码里面,是加了SEH或者VEH的, 你这个程序的执行过程如下: 执行遇 ...
哈哈哈,这个cmdline1.exe还真没有seh/veh
2020-6-8 21:07
0
雪    币: 126
活跃值: (759)
能力值: ( LV3,RANK:21 )
在线值:
发帖
回帖
粉丝
22

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming 3rd Edition>
; by 罗云彬, http://www.win32asm.com.cn
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; CmdLine.asm
; 命令行参数的获取和分析例子
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff Cmdline.asm
; Link /subsystem:windows Cmdline.obj
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        .386
        .model flat,stdcall
        option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include        windows.inc
include        user32.inc
includelib    user32.lib
include        kernel32.inc
includelib    kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        .data?
szBuffer1    db    4096 dup (?)
szBuffer2    db    4096 dup (?)
szOutput    db    8192 dup (?)

        .const
szCaption    db    '命令行参数',0
szFormat1    db    '可执行文件名称:',0dh,0ah,'%s',0dh,0ah,0ah
        db    '参数总数:%d',0dh,0ah,0
szFormat2    db    '参数[%d]:%s',0dh,0ah,0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        .code
include        _Cmdline.asm
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
        invoke    GetModuleFileName,NULL,offset szBuffer1,sizeof szBuffer1
        invoke    _argc
        mov    ebx,eax
        invoke    wsprintf,addr szOutput,addr szFormat1,addr szBuffer1,eax

        xor    esi,esi
        .while    esi < ebx
            invoke    _argv,esi,addr szBuffer2,sizeof szBuffer2
            invoke    wsprintf,addr szBuffer1,addr szFormat2,esi,addr szBuffer2
            invoke    lstrcat,addr szOutput,addr szBuffer1
            inc    esi
        .endw
        invoke    MessageBox,NULL,addr szOutput,addr szCaption,MB_OK
        invoke    ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        end    start






;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming 3rd Edition>
; by 罗云彬, http://www.win32asm.com.cn
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; _CmdLine.asm
; 命令行参数分析的通用子程序
; 功能:
; _argc ---> 对命令行参数进行数量统计
; _argv ---> 取某个命令行参数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
;
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
CHAR_BLANK    equ    20h    ;定义空格
CHAR_DELI    equ    '"'    ;定义分隔符
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 取命令行参数个数 (arg count)
; 参数个数必定大于等于 1, 参数 1 为当前执行文件名
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_argc        proc
        local    @dwArgc

        pushad
        mov    @dwArgc,0
        invoke    GetCommandLine
        mov    esi,eax
        cld
_argc_loop:
;********************************************************************
; 忽略参数之间的空格
;********************************************************************
        lodsb
        or    al,al
        jz    _argc_end
        cmp    al,CHAR_BLANK
        jz    _argc_loop
;********************************************************************
; 一个参数开始
;********************************************************************
        dec    esi
        inc    @dwArgc
_argc_loop1:
        lodsb
        or    al,al
        jz    _argc_end
        cmp    al,CHAR_BLANK
        jz    _argc_loop        ;参数结束
        cmp    al,CHAR_DELI
        jnz    _argc_loop1        ;继续处理参数内容
;********************************************************************
; 如果一个参数中的一部分有空格,则用 " " 包括
;********************************************************************
        @@:
        lodsb
        or    al,al
        jz    _argc_end
        cmp    al,CHAR_DELI
        jnz    @B
        jmp    _argc_loop1
_argc_end:
        popad
        mov    eax,@dwArgc
        ret

_argc        endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 取指定位置的命令行参数
;  argv 0 = 执行文件名
;  argv 1 = 参数1 ...
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_argv        proc    _dwArgv,_lpReturn,_dwSize
        local    @dwArgv,@dwFlag

        pushad
        inc    _dwArgv
        mov    @dwArgv,0
        mov    edi,_lpReturn

        invoke    GetCommandLine
        mov    esi,eax
        cld
_argv_loop:
;********************************************************************
; 忽略参数之间的空格
;********************************************************************
        lodsb
        or    al,al
        jz    _argv_end
        cmp    al,CHAR_BLANK
        jz    _argv_loop
;********************************************************************
; 一个参数开始
; 如果和要求的参数符合,则开始复制到返回缓冲区
;********************************************************************
        dec    esi
        inc    @dwArgv
        mov    @dwFlag,FALSE
        mov    eax,_dwArgv
        cmp    eax,@dwArgv
        jnz    @F
        mov    @dwFlag,TRUE
        @@:
_argv_loop1:
        lodsb
        or    al,al
        jz    _argv_end
        cmp    al,CHAR_BLANK
        jz    _argv_loop        ;参数结束
        cmp    al,CHAR_DELI
        jz    _argv_loop2
        cmp    _dwSize,1
        jle    @F
        cmp    @dwFlag,TRUE
        jne    @F
        stosb
        dec    _dwSize
        @@:
        jmp    _argv_loop1        ;继续处理参数内容

_argv_loop2:
        lodsb
        or    al,al
        jz    _argv_end
        cmp    al,CHAR_DELI
        jz    _argv_loop1
        cmp    _dwSize,1
        jle    @F
        cmp    @dwFlag,TRUE
        jne    @F
        stosb
        dec    _dwSize
        @@:
        jmp    _argv_loop2
_argv_end:
        xor    al,al
        stosb
        popad
        ret

_argv        endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>



这是cmdline1的源代码,我只是把其exe程序的第二条指令改为int3,来测试观点

2020-6-8 21:19
0
雪    币: 688
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23

还来****?******?班门弄斧起来了?
脸是自己拿来丢的,你有没有使用异常处理我还会不知道?
之前还有个誓言坦坦的,说他的WIN10 19041和别人的不一样的,假图都做出来了,我也装傻懒得鸟他了.
https://bbs.pediy.com/thread-259760-1.htm#1645911
现在又来一个你这样的,我就很好奇你们这些人,这些问题是不是会**************,
死撑何求啊?认个输你会*********?死撑加狡辩,**************.

最后于 2020-6-8 22:14 被kanxue编辑 ,原因:
2020-6-8 21:30
0
雪    币: 126
活跃值: (759)
能力值: ( LV3,RANK:21 )
在线值:
发帖
回帖
粉丝
24
你自己试试不就知道了,你自己随便用个没有seh/veh的exe程序试试。
这个程序是《win32汇编语言程序设计琢石城器》第十三章里的。
还我装,我忍你很久了。
我一直都是礼貌的回答你,你骂骂咧咧的就算了。
还说我人品什么的,我一个小辈都不和你计较你还在那喋喋不休。
网络上面哔哔莱莱,现实世界碰一碰。
2020-6-8 21:38
0
雪    币: 688
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25

老夫没试过会好像你这样张口就来?
你要现实是吧?125387我的Q,要约战打仗还是单P随便你,来.
你说不赢还想来打一场是吧?你如果真的认个错****************.

最后于 2020-6-8 22:16 被kanxue编辑 ,原因: 请就事论事,勿人身攻击!以理服人!
2020-6-8 21:46
0
游客
登录 | 注册 方可回帖
返回
//