控制寄存器 (CR0, CR1, CR2, CR3)(小甲鱼)

控制寄存器

(控制寄存器(CR0,CR1,CR2,CR3)用于控制和确定处理器的操作模式以及当前执行任务的特性。)
从 上表可见,80386有四个32位的控制寄存器,分别命名位CR0、CR1、CR2和CR3。但CR1被保留,供今后开发的处理器使用,在 80386中不能使用CR1,否则会引起无效指令操作异常。CR0包括指示处理器工作方式的控制位,包含启用和禁止分页管理机制的控制位,包含控制浮点协 处理器操作的控制位。CR2及CR3由分页管理机制使用。CR0中的位5—位30及CR3中的位0至位11是保留位,这些位不能是随意值,必须为0。

控制寄存器CR0的低16位等同于80286的机器状态字MSW。

1.CR0中的保护控制位

控 制寄存器CR0中的位0用PE标记,位31用PG标记,这两个位控制分段和分页管理机制的操作,所以把它们称为保护控制位。PE控制分段管理机制。 PE=0,处理器运行于实模式;PE=1,处理器运行于保护方式。PG控制分页管理机制。PG=0,禁用分页管理机制,此时分段管理机制产生的线性地址直 接作为物理地址使 用;PG=1,启用分页管理机制,此时线性地址经分页管理机制转换位物理地址。由此可知,如果要启用分页机制,那么PE和PG标志都要置位。

下 表列出了通过使用PE和PG位选择的处理器工作方式。由于只有在保护方式下才可启用分页机制,所以尽管两个位分别为0和1共可以有四种组合,但只有三种组 合方式有效。PE=0且PG=1是无效组合,因此,用PG为1且PE为0的值装入CR0寄存器将引起通用保护异常。需要注意的是,PG位的改变将使系统启 用或禁用分页机制,因而只有当所执行的程序的代码和至少有一部分数据在线性地址空间和物理地址空间具有相同的地址的情况下,才能改变PG位。

2.协处理器控制位

控制寄存器CR0中的位1—位4分别标记为MP(算术存在位)、EM(模拟位,用于选择与协处理器进行通信所使用的协议,即指明系统中是用的是80386还是80286协处理器)、TS(任务切换位) 和ET(扩展类型位),它们控制浮点协处理器的操作。

当 处理器复位时,ET位被初始化,以指示系统中数字协处理器的类型。如果系统中存在 80387协处理器,那么ET位置1;如果系统中存在80287协处理器或者不存在协处理器,那么ET位清0。EM位控制浮点指令的执行是用软件模拟,还 是由硬件执行。EM=0时,硬件控制浮点指令传送到协处理器;EM=1时,浮点指令由软件模拟。TS 位用于加快任务的切换,通过在必要时才进行协处理器切换的方法实现这一目的。每当进行任务切换时,处理器把TS置1。TS=1时,浮点指令将产生设备不可 用(DNA)异常。 MP位控制WAIT指令在TS=1时,是否产生DNA异常。MP=1和TS=1时,WAIT产生异常;MP=0时,WAIT指令忽略 TS条件,不产生异常。

在系统刚上电时,处理器被复位成pe=0,pg=0(即实模式状态),以允许引导代码在启用分段和分页机制之前能够初始化这些寄存器和数据结构。对于这类寄存器的使用是在实模式下方可使用。

3.CR2和CR3

控制寄存器CR2和CR3由分页管理机制使用。
CR2用于发生页异常时报告出错信息。当发生页异常时,处理器把引起页异常的线性地址保存在CR2中。操作系统中的页异常处理程序可以检查CR2的内容,从而查出线性地址空间中的哪一页引起本次异常。

CR3 用于保存页目录表页面的物理地址,因此被称为PDBR。由于目录是页对齐的,所以仅高20位有效,低12 位保留供更加高级的处理器使用。向CR3中装入一个新值时,低12位必须为0;但从 CR3中取值时,低12位被忽略。每当用MOV指令重置CR3的值时,会导致分页机制高速缓冲区的内容无效,用此方法,可以在启用分页机制之前,即把PG 位置1之前,预先刷新分页机制的高速缓存。CR3寄存器即使在CR0寄存器的PG位或PE位为0时也可装入,如在实模式下也可设置CR3,以便进行分页机 制的初始化。在任务切换时,CR3要被改变,但是如果新任务中CR3的值与原任务中CR3的值相同,那么处理器不刷新分页高速缓存,以便当任务共享页表时 有较快的执行速度。

状态和控制寄存器组除了EFLAGS、EIP ,还有四个32位的控制寄存器,它们是CR0,CR1,CR2和CR3。这几个寄存器中保存全局性和任务无关的机器状态。

CR0 中包含了6个预定义标志,0位是保护允许位PE(Protedted Enable),用于启动保护模式,如果PE位置1,则保护模式启动,如果PE=0,则在实模式下运行。1位是监控协处理位MP(Moniter coprocessor),它与第3位一起决定:当TS=1时操作码WAIT是否产生一个“协处理器不能使用”的出错信号。第3位是任务转换位(Task Switch),当一个任务转换完成之后,自动将它置1。

随着TS=1,就不能使用协处理器。CR0的第2位是模拟协处理器位 EM (Emulate coprocessor),如果EM=1,则不能使用协处理器,如果EM=0,则允许使用协处理器。第4位是微处理器的扩展类型位 ET(Processor Extension Type),其内保存着处理器扩展类型的信息,如果ET=0,则标识系统使用的是287协处理器,如果 ET=1,则表示系统使用的是387浮点协处理器。CR0的第31位是分页允许位(Paging Enable),它表示芯片上的分页部件是否允许工作。

CR1是未定义的控制寄存器,供将来的处理器使用。
CR2是页故障线性地址寄存器,保存最后一次出现页故障的全32位线性地址。
CR3是页目录基址寄存器,保存页目录表的物理地址,页目录表总是放在以4K字节为单位的存储器边界上,因此,它的地址的低12位总为0,不起作用,即使写上内容,也不会被理会。

这几个寄存器是与分页机制密切相关的,因此,在进程管理及虚拟内存管理中会涉及到这几个寄存器,读者要记住CR0、CR2及CR3这三个寄存器的内容。

相关路径及screen常用命令(centos6)

ssh相关路径:

/etc/host.deny

/etc/host.allow

/etc/ssh/

/etc/ssh/sshd_config

screen相关路径:

/etc/screenrc

$HOME/.screenrc

screen常用命令:

C-a ? 显示所有键绑定信息

C-a w 显示所有窗口列表

C-a C-a 切换到之前显示的窗口

C-a c 创建一个新的运行shell的窗口并切换到该窗口

C-a n 切换到下一个窗口

C-a p 切换到前一个窗口(与C-a n相对)

C-a 0..9 切换到窗口0..9

C-a a 发送 C-a到当前窗口

C-a d 暂时断开screen会话

C-a k 杀掉当前窗口

C-a [ 进入拷贝/回滚

………………………………………………

-c file 使用配置文件file,而不使用默认的$HOME/.screenrc

-d|-D [pid.tty.host] 不开启新的screen会话,而是断开其他正在运行的screen会话

-h num 指定历史回滚缓冲区大小为num行

-list|-ls 列出现有screen会话,格式为pid.tty.host

-d -m 启动一个开始就处于断开模式的会话

-r sessionowner/ [pid.tty.host] 重新连接一个断开的会话。多用户模式下连接到其他用户screen会话需要指定sessionowner,需要setuid-root权限

-S sessionname 创建screen会话时为会话指定一个名字

-v 显示screen版本信息

-wipe [match] 同-list,但删掉那些无法连接的会话

ngnix相关

今天设置vsftpd和ngnix新建虚拟主机的时候出了很多错,究其本源,还是ngnix掌握不熟练,所以找些资料,时而复习之。

1.NGINX启动:首先找到NGINX执行文件。

 

-C参数代表制定的配置文件。不加的话,默认加载安装目录的conf目录的配置文件。

2.NGINX停止

我需要用KILL命令来做.

首先找到主进程号:

Ps -ef |grep ’nginx’

 

第一行:master process 表示主进程号。3176.为ID号

我们直接结束即可。

kill -QUIT 3176就OK了。

3.有时候我们修改配置文件。需要让它被使用。NGINX和APACHE有些不同。

NGINX有一个概念叫做平滑重启。其实就是发送信号给NGINX的主进程方式进行的。

再重启之前我们需要确认nginx配置文件是否正确。否则他不会加载新的配置文件。

 

如上图一样。配置文件没问题。

下面要做的是重启。Kill -HUP 主进程号 或者kill -HUP nginx.pid的路径

但是大家要注意。这里重启。主进程号是不变的,所以大家不要误会。没有重启成功.

4.NGINX有几个信号控制.:

QUIT 从容关闭

HUP 平滑重启,重新加载配置文件的

USER1 重新打开日志文件,主要用于日志文件的切割.

5.NGINX日志配置

NGINX 日志指令。有2个。一个是log-format(设置格式的),一个是access_log(存放路径等信息).

简单介绍下log_format.

语法:log-format name [format]

Name 表示格式的名称。Format表示格式的样式或者说有哪些内容。

wwwlogs是定义格式的名字.

$remote_addr 客户端名称

$remote_user 客户端账号。不过基本没啥用

[$time_local] 访问时间

$request请求的URL以及HTTP

$status 用于请求的状态:404,200之类的东西

$body_bytes_set 传输内容大小

$http_referer  从哪个页面访问过来的

$http_user_agent  浏览器信息

$http_x_forwarded-for 主要是记录客户端IP(当nginx作为负载均衡时候,反代理之后。我们获取的IP可能不正确。所以用这个获取真实的IP。)

$quest_time表示回应的时间,可以称作响应时间。(一般用于对程序分析效率)

 

Access_log

 

主要是存储目录。

 

 

 

6.NGINX日志切割

NGINX不知此像APACHE那样的cronlog

我们只能自己写脚本来控制。用crontab 来跑程序。

首先用mv 剪切

Mv /los/access.log  /totallog/20110101.log

Kill -user1 NGINX主进程号(会重新监理日志文件)

下面我写一个SHELL:

然后设置下crontab 来跑这个脚本就ok了.

写个stl程序

明天就要acm课考试了,可是一学期几乎没去上过课(感觉有点对不住lcy老师啊。、、),肿么办。。没办法,只能临时抱抱佛脚,于是拿出了尘封已久的《算法竞赛入门经典》,话说当初刚接触acm的时候真心挺佩服刘汝佳的,大神啊,大二是就是世界第四了。可一年多过去后发现自己对这个没多少兴趣了。。

闲话不多说,切入正题,翻书的时候看到这样一道小题:

移动小球

你有一些小球,从左到右依次编号为1,2,3,……,n。指令A x y表示把小球x移动到小球y左边,B x y表示把小球x移动到小球y右边。指令保证合法(x不等于y)。输入小球个数n和指令条数m及m条指令,从左至右输出最后的序列。n可高达500000,m可高达100000.

样例输入:

6 2

A 1 4

B 3 5

样例输出:

2 1 4 5 3 6

 

这道题时间规模很大,因此书上采用数组模拟链表的方式实现。详见书。。

这里给出我的一个解法,用stl的list容器。

代码如下:

#include<iostream>
#include<list>
#include<algorithm>
using namespace std;
int main()
{
int n,m,x,y;
char type[3];
list<int> ball;
list<int>::iterator it;
while(scanf(“%d%d”,&n,&m)!=EOF)
{
for(int i=1;i<=n+1;i++)
ball.push_back(i);
for(int j=1;j<=m;j++)
{
scanf(“%s%d%d”,type,&x,&y);
if(type[0]==’A')
{
it=find(ball.begin(),ball.end(),y);
ball.remove(x);
ball.insert(it,x);
}
else
{
it=find(ball.begin(),ball.end(),y);
ball.remove(x);
ball.insert(++it,x);
}
}
ball.pop_back();
for(it=ball.begin();it!=ball.end();it++)
{
cout<<*it<<’ ‘;
}
cout<<endl;
ball.clear();
}
return 0;
}

这里有一点值得注意,因为list的迭代器不能实现+1等随机遍历(list实质是链表),所以只好用++操作替代,因而可能造成迭代器越界(find()返回ball.end()时)。所以这里我多创建一个元素,在输出前删除。由于使用while(scanf()!=EOF),所以每组数据结束后都要清空ball。

初识Greasemonkey

1. 每个用户脚本后缀名必须是.user.js,例如:helloworld.user.js,其内容:

// ==UserScript==
// @name          Hello World
// @namespace     http://diveintogreasemonkey.org/download/
// @description   example script to alert "Hello world!" on every page
// @include       *
// @exclude       http://diveintogreasemonkey.org/*
// @exclude       http://www.diveintogreasemonkey.org/*
// ==/UserScript==

alert('Hello world!');

2. 分析一下用户脚本元数据

用//==UserScript==与//==/UserScript==用于标识脚本的起始,其中包含6行元数据描述。这段注释可以放在脚本的任何位置,但是一般来说是放在脚本的顶部。

//@name Hello World

这是定义你脚本的名子,它将显示在安装对话框中,以及在“Manage User Scripts”对话框。这个名子应该简短并且能够表达脚本的含义。这个元数据可以被省略,如果省略,默认是脚本文件名减去.user.js扩展名。

//@namespace http://diveintogreasemonkey.org/download/

这个元数据一般是URL,用于区分具有相同名子的脚本,如果你有一个域名,你可以使用域名,否则你可以用tag:URI。这个元数据也可以被省略,如果省略,默认使用下载脚本的域名。

//@description  example script to alert “Hello world!” on every page

这个元数据用于定义可读的描述信息,最好不要超过两句。这个信息将会显示在安装对话框和“Manage User Scripts”对话框。当然,这个元数据可以被省略,默认值是空字符串。

// @include       * // @exclude       http://diveintogreasemonkey.org/*
// @exclude       http://www.diveintogreasemonkey.org/*

@include与@exclude用于定义脚本可以用于哪些站点,*是通配符。上面的例子就是说,脚本可以用在所有站点,除了http://diveintogreasemonkey.org/*与http://www.diveintogreasemonkey.org/*。这两个元数据都可以被省略,如果这两个元数据没有被定义,那么脚本将被用于所有站点。

3. 编写用户脚本

alert('Hello world!');

当然,以上就是脚本的真正逻辑。其实为了避免你的脚本程序与要注入的页面中原有的脚本冲突,Greasemonkey在幕后帮你做了很多事情,他把你的代 码包装成匿名函数,虽然你可以忽略这些,但是这里却有个潜在的问题,你所定义的变量或函数不可以被其它的脚本调用。举例来说:

function helloworld() {
    alert('Hello world!');
}

window.setTimeout("helloworld()", 60);

以上的脚本一定会报错(”helloworld is not defined” ),这是因为当一个用户脚本执行完一次后,变量或函数便失效,这就意味着当你期待使用window.setTimeout函数调用你自己的函数时,便会报 错。解决的办法是你可以将你的函数定义成window对象的属性,例如:

window.helloworld = function() {
    alert('Hello world!');
}

window.setTimeout("helloworld()", 60);

然后,这并不是一个最好的解决方案,因为很有可能你要注入脚本的页面中也定义了相同名称的window对象属性,这样就会引起冲突,最好的方案是你定义一个匿名函数,并将其作为参数传递给window.setTimeout。例如:

window.setTimeout(function() { alert('Hello world!') }, 60);

shell编程笔记

大一上学期的一些笔记:

1.linux系统地服务启动的借口在etc/init.d/目录下
2.启动加载程序的项目/etc/rc.d/rc.local里的数据
3.命令、参数间的多个空白都会被忽略掉
4.sh shell.sh
sh的参数:
-n
-x
5.开头必须:
#!/bin/bash
6.exit 0表示结束script并会传一个0给系统
7.交互式脚本常用命令:read
read -p “提示字符串” 变量名
8.date –date=string    列出相应日期。
date +%Y%m%d        按指定格式显示
如:
date –date=”2 days ago” +%Y%m%d
9.declare    定义变量类型
数值计算:$((计算式))
10.script的执行方式区别:
直接命令执行(绝对路径/相对路径/$PATH内),或是bash或sh来执行,script都会使用一个新的bash来执行(即子进程)。所以创建的变量在父进程内无效
而用.或source执行,则是在父进程内执行,创建的变量有效
11.test        测试
文件类型判断:
-e    是否存在
-f    是否存在且为文件
-d    是否存在且为目录
文件权限检测:
-r
-w
-x
-u
-g
-k    是否有Sticky bit属性
-s    是否存在且为“非空白文件”
两个文件比较:
test file1 -nt file2
-nt    (newer than)判断file1是否比file2新
-ot    (old than)判断file1是否比file2旧
-ef    判断file1和file2是否为同一文件,用于hard link的判断上。主要意义在于判定两个文件是否均指向同一个inode
两个整数之间的判定:
test n1 -eq n2
-eq    两值相等
-ne    两值不等
-gt    n1大于n2
-lt    n1小于n2
-ge    n1大于等于n2
-le    n1小于等于n2
判字符串;
test -z string    判字符串是否为0,若string为空字符串,则为true
test string    string是否非零,非空为true
test str1=str2    相等传true
test str1!=str2    不等传true
多重判定(重要):
-a    同时成立传true。如test -r file -a -x file,file同时具有r与x权限时回传true
-o    任何一个状态成立回传true
!    反向状态,

win32汇编笔记

大一上学期的一些笔记:

1.一个应用程序可能有多个窗口。
2.一个应用程序实例(进程)只有一个消息队列。
3.每个窗口都有自己的窗口过程(回调函数)。
4.操作系统有自己的一个系统消息队列。
5.消息循环的各个api在user32.dll中。
6.PostMessage将消息放入指定程序的消息队列中。
SendMessage将消息直接传给对应的窗口过程(callback函数)。
PostQuitMessage将WM_QUIT消息传给消息循环。
8.RegisterClass的参数为指向结构体WndClass的指针。
9.WndClass的lpfnWndProc参数放窗口过程的地址。
10.窗口过程(callback函数)用于处理传入的消息。
11.有些实时性很强的消息如SetCursor等不通过Dispatch函数的派发,而是直接由系统调用窗口过程。
一个win32窗口程序的源程序模板:
_WinMain函数:
获取窗口句柄GetModuleHandle
注册类RegisterClassEx
建立并显示窗口CreateWindowEx  ShowWindowEx  UpdateWindowEx
消息循环GetMessage(进入user32.dll由系统取消息)  (TanslateMessage等(非必要)) DispatchMessage(进入user32.dll由系统调用窗口过程)
_ProcWinMain函数:
窗口过程,用于接收和处理消息
主函数:
call _WinMain
invoke ExitProcess NULL

12.RtlZeroMemory,@stWndClass,sizeof @stWndClass用于将结构体变量@stWndClass各成员置0.局部变量初始化十分重要,要牢记。
13.WNDCLASSEX结构体
cbsize
style        CS_VREDRAW CS_HREDRAW CS_KEYCVTWINDOW CS_DBLCLKS等等
lpfnwndproc
cbclsextra    保留
cbwndextra    保留
hinstance
hicon
hcursor        光标句柄,指定光标形状
hbrbackground    BRUSH句柄(也可以使用颜色值,如:COLOR_BACKGROUND COLOR_HIGHLIGHT COLOR_MENU COLOR_WINDOW     注:使用颜色值时后面+1)
lpszmenuname
lpszclassname
hiconsm        小图标

14.获取BRUSH的句柄:用函数GetStockObject(如:invoke getstockobject,WHITE_BRUSH)
15.CreateWindowEx,dwExStyle,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hwWndParent,hMenu,hInstance,lpParam
hMenu    菜单句柄,当dwStyle为WS_CHILD时,表示子窗口ID,子窗口没有菜单
16.WNDCLASSEX中的style(默认风格)中的值开头为CS_(CLASS STYLE),CreateWindowEx中的dwStyle的值开头为WS_(WINDOW STYLE)
17.dwExStyle的值也要牢记。。
18.hinstance是模块句柄,也就是一个应用程序实例的句柄。一个应用程序实例可能会有多个窗口。另外,一个窗口也有句柄。两者不可混淆!!
19.createwindowex返回建立的窗口的句柄。
20.类是一个应用程序实例的,所以WNDCLASSEX中才有个参数hInstance,用于取得模块句柄。
21.Button和Edit等都是子窗口。
22.程序开始时,系统会发送WM_CREATE消息到模块的消息队列中,消息循环开始后就会从消息队列读取该消息并传到窗口过程(本人猜测)

关于消息循环:
.while TURE
invoke GetMessage,addr @stmsg,NULL,0,0    (从消息队列取消息)
.break .if eax==0
invoke TranslateMessage,addr @stmsg(非必要,将一些键盘扫描码消息转为键盘ascii码消息)
invoke DispatchMessage,addr @stmsg(将消息派发给相应窗口过程)
.endw
MSG结构体:
hwnd    消息要发向的窗口句柄(注意:不是模块句柄)
message
wParam
lParam
time
pt    POINT结构体,表示消息放入消息队列时的鼠标坐标
23.createwindowex时用了某个类也就用了该类中确定的窗口过程
24.一个应用程序实例(模块)只有一个消息队列,一个消息循环,但可能有多个窗口,因此也就有可能有多个窗口过程。
25.GetMessage原型:
GetMessage,lpMsg,hWnd,wMsgfiltermin,wMsgfiltermax
lpMsg:指向一个MSG变量的指针
hWnd:表示要获取发向哪个窗口的消息。NULL表示获取本应用程序的所有消息。
后两个参数:指定获取特定编号范围的消息。0表示获取所有编号的消息。
26.WM_QUIT消息的返回值为0
27.当有按键按下或放开时触发消息:WM_KEYDOWN或WM_KEYUP或WM_SYSKEYDOWN或WM_SYSKEYUP
但其值为扫描码,TranslateMessage将其转化成WM_CHAR或WM_SYSCHAR消息。
28.遇到非键盘消息,TranslateMessage不做处理。
29.windows是抢占式多任务系统,任务间每20ms切换一次。
30.关于窗口过程:
WindowProc proc hwnd,uMsg,wParam,lParam
hwnd    要操作的窗口句柄
一个窗口过程可能会为基于同一个类的多个窗口服务,所以要指定窗口句柄。
这四个参数与MSG结构的前四个参数相同。
一条消息(MSG类型变量)中的hwnd指定了要操作哪个窗口。
不同消息后两个参数值代表的意义不同。
callback函数的返回值:
处理不同消息,返回不同值。
如:处理WM_CREATE消息时返回0表示执行成功,返回-1表示执行失败。
createwindowex时向窗口过程收到的消息:
WM_GETMINMAXINFO    获取窗口大小以便初始化
WM_NCCREATE        非客户区建立
WM_NCCALCSIZE        计算客户区大小
WM_CREATE        窗口建立
updatewindow时窗口过程收到的消息只有一条:WM_PAINT
31.单击窗口右上角关闭按钮触发WM_CLOSE消息
if uMsg == WM_CLOSE
invoke DestroyWindow…………
invoke PostQuitMessage,NULL(该函数会发送WM_QUIT消息给消息循环)  这个函数的参数就是WM_QUIT消息的MSG结构的wParam
32.结束程序时务必在摧毁窗口后用postquitmessage函数向消息循环发送WM_QUIT消息以退出消息循环。这一点很重要。
33.PostMessage,hWnd,Msg,wParam,lParam
SendMessage,hWnd,Msg,wParam,lParam
34.wsprintf是win32 api中唯一一个参数个数不定的函数。
35.FindWindow,lpClassName,lpWindowName(返回找到窗口的句柄)
36.不同消息的wParam和lParam是不同的。
37.WM_COPYDATA消息的COPYDATASTRUCT结构:
COPYDATASTRUCT
dwData    DWORD    ?    ;附加字段
cbData    DWORD    ?    ;数据长度
lpData    DWORD    ?    ;数据位置指针
COPYDATASTRUCT    ENDS
资源
38.资源源文件中
菜单 ID MENU [DISCARDABLE]指定菜单的ID值和内存属性
数值型ID的范围:1~65535    字符串在内存中的线性地址总是大于10000h
菜单项:
menuitem 菜单文字,命令ID[,选项列表]
或menuitem SEPARATOR
或popup 菜单文字[,选项列表]
命令ID:但菜单被选中时会发送WM_COMMAND消息,消息的参数就是命令ID
39菜单的装载:
菜单可以在createwindowex中的参数hMenu指定句柄,那么菜单句柄如何获得?用api:LordMenu,hInstance,菜单的ID
40.WM_COMMAND的两个消息:
wParam高位=wNotifyCode    通知码
wParam低位=wID        命令ID
lParam=hwndCtl        发送消息的子窗口句柄(工具栏、按钮等)(对于菜单或加速键引起的WM_COMMAND消息则lParam为0)
菜单消息的通知码是0,加速键消息的通知码是1
程序运行中动态修改菜单:
AppendMenu,hMenu,uFlag,uIDNewItem,lpNewItem
InsertMenu,hMenu,uPosition,uFlags,uIDNewItem,lpNewItem
ModifyMenu,hMenu,uPosition,uFlags,uIDNewItem,lpNewItem
DeleteMenu,hMenu,uPosition,uFlags
RemoveMenu,hMenu,uPosition,uFlags
uFlags一般用两种值:MF_BYCOMMAND  MF_BYPPOSITION
对于popup菜单
DeleteMenu:全删
RemoveMenu:仅移去菜单项,菜单在内存中还是存在的(可以在其他地方引用)
对于非popup菜单,两者相同
41.系统菜单:指按下了标题栏图标后弹出的菜单。
42.选中系统菜单项发送WM_SYSCOMMAND消息
系统菜单的句柄:GetSystemMenu,hWnd,FALSE
系统菜单的默认菜单项的命令ID(系统预定义):
保存    SC_RESTORE
移动    SC_MOVE
大小    SC_SIZE
最小化    SC_MINIMIZE
最大化    SC_MAXIMIZE
关闭    SC_CLOSE
43.右键弹出菜单
TrackPopupMenu,hMenu,uFlags,x,y,nReserved,hWnd,lpRect
该函数执行后在x,y处弹出属于hWnd窗口的菜单(即WM_COMMAND消息发往该窗口)(x,y以屏幕左上角为基准)
uFlags:一般用TPM_LEFTALIGN
该参数还可用于指定用左键还是右键选定菜单项:TPM_LEFTBUTTON   TPM_RIGHTBUTTON
lpRect指向一个RECT结构,用于指定一个区域,在这个区域外单击鼠标菜单才会消失,如果为NULL,则在菜单外单击,菜单就会消失。
在客户区右击弹出菜单,所以要处理WM_RBUTTONDOWN消息。在该消息中调用TrackPopupMenu
一般在单击处弹出菜单,所以要要获取鼠标坐标GetCursorPos,lpPoint
lpPoint指向POINT结构
POINT    STRUCT
x  DWORD  ?
y  DWORD  ?
POINT    ENDS
LordMenu载入的不是popup菜单,popup只能在第二层及以下。用GetSubMenu
invoke GetSubMenu,hMenu,nPos
.if eax
mov hSubMenu,eax
.endif
nPos:菜单项的索引,从0开始
右键菜单一般性代码范例:
local:@stPos:POINT
……
invoke GetCursor,addr @stPos
invoke TrackPopupMenu,hSubMenu,TPM_LEFTALIGN,@stPos.x,@stPos.y,NULL,hWnd,NULL
44.菜单将激活,即用户在菜单上按动鼠标时,windows在菜单弹出之前会向窗口过程发送WM_INITMENU消息,可以在这个消息的处理中进行菜单项的检测和设置:
GetMenuState,hMenu,uId,uFlags
GetMenuState函数的返回值:
失败返回-1
成功则:
MF_CHECKED
MF_DISABLED
MF_GRAYED
MF_HILITE高亮
MF_MENUBARBREAK
MF_MENUBREAK
MF_SEPARATOR
以上的组合值
如何检测菜单状态:
invoke GetMenuState,hMenu,IDM_XXX,MF_BYCOMMAND
.if eax&MF_CHECKED(表示菜单项选中)
…………
.endif

EnableMenuItem,hMenu,uIDEnableItem,uEnable(uEnable取值:MF_ENABLED  MF_DISABLED  MF_GRAYED)(菜单项在可用、禁用、灰化之间转化)
CheckMenuItem,hMenu,uIDCheckItem,uCheck(uCheck取值:MF_CHECKED  MF_UNCHECKED)
CheckMenuRadioItem,hMenu,idFist,idLast,idCheck,uFlags
45.没有与窗口相连的菜单要用DestroyMenu来释放内存
SetMenu,hWnd,hMenu用于在不同情况下给程序以不同的菜单(如未打开文件和打开文件下窗口的菜单是不同的,这就需要在rc文件中建多个菜单)

c语言win32 sdk笔记

大一上学期的一些笔记

GetShortPathName(“”,shortpath,sizeof shortpath)
mciSendString(cmd,”",0,NULL)
mciSendString的声明在mmsystem.h中
OPENFILENAME结构体
lStructSize=sizeof(ofn);
lpstrFile=szfile;
lpstrFile[0]=TEXT(‘’);
nMaxFile=sizeof(szfile);
lpstrFilter=TEXT(“all*.*text*.txtmp3*.mp3……”);
nFilterIndex=1;
lpstrFileTitle=NULL;
nMaxFileTitle=0;
lpstrInitialDir=NULL;
hwndOwner=hwnd;
Flags=OFN_EXPLORER|OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST

ZeroMemory函数:局部变量的置0
zeromemory(&结构体名,sizeof(结构体名));

socket编程:
windows独有的函数都以WSA开头。
api执行完后结果放到lasterror中
GetLastError()
FormatMessage()将错误码转换为错误消息
recv(sock,buffer,sizeof(buffer)/sizeof(TCHAR),0)
send(sock,buffer,sizeof(buffer)/sizeof(TCHAR),0)

逆向笔记

大一上学期的一些笔记:

1.用堆栈存放局部变量
编译器非优化模式下用ebp寻址。ebp-xxxx    参数则为ebp+xxxx
编译器优化模式下用esp直接寻址
2.局部变量分配与清除堆栈:
一、sub esp,n
…………
add esp,n
二、add esp,-n
…………
sub esp,-n
三、push reg(reg为某个寄存器)
…………
pop reg
3.利用寄存器存放局部变量:
如果寄存器不够用,会利用堆栈。逆向时必须及时确定当前寄存器的变量是哪个变量。
4.如果函数有两个参数,用ebp传址,则两参数地址一般为ebp+08  ebp+0c
push ebp
mov ebp,esp
push ecx
mov eax,dword ptr [ebp+08]
mov ecx,dword ptr [ebp+0c]
………………
5。全局变量一般位于.idata区的一个固定地址上,访问时直接用硬编码的地址直接对内存寻址.
6.数组:基址加变址寻址
7.开始时xor一个寄存器往往是将其作为一个变量使用。
【基址+n】一般为给数组或结构赋值,其中基址为常量或寄存器。
8.lea有时等价于add
lea eax,[eax+8]等价于add eax+8
lea的效率远远高于add,这种技巧可以使多个变量的求和在一个指令周期内完成
9.大写字母:41h——5Ah大写字母的第5位为0
小写字母:61h——7Ah小写字母的第5位为1
10.c语言strlen()在优化模式下的汇编代码:
mov ecx,FFFFFFFF    ;如果看到这句,程序很可能是要获得字符串的长度了
sub eax,eax
repnz
scasb
not ecx
dec ecx
je xxxxxxxx
11.测试寄存器是否为0:
cmp eax,00000000h

or eax,eax

test eax,eax
12.置寄存器0FFFFFFFFh
xor eax,eax/sub eax,eax
dec eax

stc
sbb eax,eax
13.转移指令:
jmp _lable_

push _lable_
ret
14.获取编辑框字符串常用api:
GetWindowTextA(W)
GetDlgItemTextA(W)
GetDlgItemInt
判断完注册码后常常显示对话框,告诉用户是否正确,显示对话框的常用api:
MessageBoxA(W)
MessageBoxExA(W)
MessageboxIndirectA(W)
DialogBoxParamA(W)
DialogboxIndirectParamA(W)
CreateDialogParamA(W)
CreateDialogIndirectParamA(W)
ShowWindow
程序每次启动都会将注册码读出来加以判断,决定是否以注册版的模式工作,根据序列号放置位置不同,可用不同的api断点:
(1)序列号在注册表中:可用RegQueryValueExA(W)
(2)序列号在ini文件中:可用GetPrivateProfileStringA(W)、GetPrivateProfileIntA(W)、GetProfileStringA(W)、GetProfileIntA(W)
(3)序列号在一般文件中,CreateFileA(W)、_lopen()
15.数据约束性(密码相邻性):(仅限于明文比较注册码的保护方式)真正正确的注册码会在某个时刻出现在内存中,但位置不定。大多数情况下会在输入序列号的内存地址+-90h的地方。它们会共同位于一个小堆栈区域(加密者一般用局部变量放临时计算出来的注册码),使得它们可以在同一个watch窗口中看到。
16.模块句柄hInstance是实例的基地址
17.DialogBoxParam函数原型:
int DialogBoxParam(
HINSTANCE hInstance,    模块句柄
LPCTSTR lpTemplateName,    对话框ID
HWND hWndParent,    父窗口句柄
DLGPROC lpDialogFunc,    对话框处理函数指针(程序会跳到这里执行)
LPARAM dwInitParam    初始化值
);
18.去除某个对话框的方法:
先用exescope打开查看资源,若对话框为资源,记下ID,用w32dasm,打开对话框参考,找到对应id的对话框,双击来到代码处。
若为DialogBoxParam,用jmp跳过(EndDialog后面)
若主窗口也为DialogBoxParam则可修改前一个DialogBoxParam的TemplateName和lpDialogFunc使之指向主窗口。
对话框不是资源时,而常用断点又拦不下来,这是可以试试消息断点。如WM_DESTROY。
19.时间限制:
(1)每次运行多少时间
(2)时间段限制,如用30天
(1)
SetTimer函数:
UINT SetTimer(HWND hWnd,UINT nIDEvent,UINT uElapse,TIMERPROC lpTimerFunc)
hWnd        窗口句柄
nIDEvent    计时器标识
uElapse        指定计时器时间间隔,单位毫秒
lpTimerFunc    回调函数,超时时系统调用该函数,如果为NULL,则超时将向相应窗口发送WM_TIMER消息
该callback函数原型:
void CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime);
KillTimer()销毁计时器
timeSetEvent(…………)多媒体计时器
GetTickCount()返回系统自成功启动以来的时间(毫秒数)(两次调用相减就得到程序运行时间)
c语言用time()获取系统时间
(2)
取得时间的api:
GetSystemTime
GetLocalTime
GetFileTime
软件主要记录两个时间:
(1)首次运行时间
(2)上次运行时间(每次运行时都获取一次系统时间,若大于上次运行时间,则更新,不然则说明用户将系统时间改回去了)
时间一般记录在注册表或文件或扇区中,不起眼的地方
#define WM_TIMER 0×0113
可见WM_TIMER就是0×0113

json的资料

json是种轻量级格式。json类似于键值对,但可以表示复杂得多的结构,可以嵌套对象(个人理解)。

json有两种结:

1. “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),记录(record),结构(struct),字典(dictionary),哈希表 (hash table),有键列表(keyed list),或者关联数组 (associative array)。

2.值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。

json对象的获取,访问,修改:

将 JSON 数据赋值给变量

例如,可以创建一个新的 JavaScript 变量,然后将 JSON 格式的数据字符串直接赋值给它:   var people = { “programmers”: [ { "firstName": "Brett", "lastName":"McLaughlin", "email": "aaaa" },   { "firstName": "Jason", "lastName":"Hunter", "email": "bbbb" },   { "firstName": "Elliotte", "lastName":"Harold", "email": "cccc" }   ],

“authors”: [   { "firstName": "Isaac", "lastName": "Asimov", "genre": "science fiction" },   { "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },   { "firstName": "Frank", "lastName": "Peretti", "genre": "christian fiction" }   ],

“musicians”: [   { "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },   { "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }   ] }   这非常简单;现在 people包含前面看到的 JSON 格式的数据。但是,这还不够,因为访问数据的方式似乎还不明显。

访问数据

尽管看起来不明显,但是上面的长字符串实际上只是一个数组;将这个数组放进 JavaScript 变量之后,就可以很轻松地访问它。实际上,只需用点号表示法来表示数组元素。所以,要想访问 programmers 列表的第一个条目的姓氏,只需在 JavaScript 中使用下面这样的代码:   people.programmers[0].lastName;   注意,数组索引是从零开始的。所以,这行代码首先访问 people变量中的数据;然后移动到称为 programmers的条目,再移动到第一个记录([0]);最后,访问 lastName键的值。结果是字符串值 “McLaughlin”。   下面是使用同一变量的几个示例。   people.authors[1].genre // Value is “fantasy”   people.musicians[3].lastName // Undefined. This refers to the fourth entry, and there isn’t one   people.programmers[2].firstName // Value is “Elliotte”   利用这样的语法,可以处理任何 JSON 格式的数据,而不需要使用任何额外的 JavaScript 工具包或 API。

修改 JSON 数据

正如可以用点号和括号访问数据,也可以按照同样的方式轻松地修改数据:   people.musicians[1].lastName = “Rachmaninov”;   在将字符串转换为 JavaScript 对象之后,就可以像这样修改变量中的数据。

转换回字符串

String newJSONtext = people.toJSONString();

可以将 任何JavaScript 对象转换为 JSON 文本。并非只能处理原来用 JSON 字符串赋值的变量。为了对名为 myObject的对象进行转换,只需执行相同形式的命令:

String myObjectInJSON = myObject.toJSONString();

下面是和xml之间的对比:

(例子来自百度)

用XML表示部分省市数据如下:

<?xml version=”1.0″ encoding=”utf-8″?>

<country>

<name>中国</name>

<province>

<name>黑龙江</name>

<cities>

<city>哈尔滨</city>

<city>大庆</city>

</cities>

</province>

<province>

<name>广东</name>

<cities>

<city>广州</city>

<city>深圳</city>

<city>珠海</city>

</cities>

</province>

<province>

<name>台湾</name>

<cities>

<city>台北</city>

<city>高雄</city>

</cities>

</province>

<province>

<name>新疆</name>

<cities>

<city>乌鲁木齐</city>

</cities>

</province>

</country>

用JSON表示如下:

{

name:”中国”,

province:[

{

name:"黑龙江",

cities:{

city:["哈尔滨","大庆"]

}

},

{

name:”广东”,

cities:{

city:["广州","深圳","珠海"]

}

},

{

name:”台湾”,

cities:{

city:["台北","高雄"]

}

},

{

name:”新疆”,

cities:{

city:["乌鲁木齐"]

}

}

]

}

很明显,xml的可读性高于json,但是不适合人读的往往适合计算机读,json这是如此,json相当高效。

JSON在线校验工具:

BeJson

关于linux的参数执行顺序。。

        今天在看正则表达式的时候遇到了两个问题,用vi打开/etc下的sysctl.conf的时候会发现有许多空白行和注释行。但是有时候stdout的时 候并不需要这些信息,若是打印时则更能节省纸张资源。-_-!于是我用grep命令将其去除,具体指令为grep -v ‘^$’ /etc/sysctl.conf|grep -v ‘^#’可是运行完该句之后的结果着实让我头疼,因为我发现注释行仍然出现了,而且前面还多了一个数字。往上一检查才发现自己多打了一个n。。命令变成了 grep -vn ‘^$’ /etc/sysctl.conf|grep -v ‘^#’。
        这对我来说是个不错的收获。因为大家都知道管道命令会把前者的stdout转换为后者的stdin,而碰巧的是n正好有是grep的一个参数,用于输出行 号。于是后者的stdin的每行的开始都有了行号。这样每行的开始都不是#字符了,注释也就自然没被去除。看来管理时真的要小心谨慎,一不小心结果就会发 生错误。另外,如果有些童鞋在不是自己的主机上执行该命令的时候会发现命令完全正确,可是结果还是有类似错误。这时候很可能是因为grep被该用户 alias过的原因。比如该用户alias grep=’grep -v’.这样会有更奇怪的结果哦(会有两列行号^_^)当然这点如果多执行命令的话也是可以发现的,其实type grep一下就·ok。而且一般人不会这么做,毕竟v用于显示没有指定字符串的行。如果真是这个原因,怎么改呢?很简单,去改下用户目录下 的.bashrc文件吧。这个是login shell会读取的文件。里面会初始化一些命令别名,然后会注册一些环境变量。login时会被~/.bash_profile调用。如果发现grep被 alias成带v参数,就赶紧把它注释掉吧。要想立刻生效的话,手动读取一下吧。source ~/.bashrc 这样就ok了。
这时候,,又想到一个问题,上述命令中的参数v和n是哪个先执行呢。联系到最近在win32汇编上学的c调用、stdcall都是右边参数先入栈来看的 话,我想linux应该也类似吧(。。。纯属个人胡扯~~~~)。那样应该是自左向右顺序执行的。从结果来看,空行确实被去除了,那是不是真的是自左向右 的顺序呢。于是验证了一下。grep -nv ‘^$’ /etc/sysctl.conf|grep -v ‘^#’结果空行还是被去除了。看来假设不对。如果自左向右,那么-n执行后每行都有行号,再执行-v不会去除空行。当然这里有个问题,那就是我不清楚第 一个参数执行后是否真正影响了输出,如果行号没被算进去的话执行-v后还是会去除空行的。这样参数执行顺序的问题还是不敢下定论。。可是大年夜的没有网络 可用。看来有机会得去百度一下了。。
不过,这时候,,,天亮了。。下午四五点起床的孩子通宵无压力。。O~睡觉去了。。。
以上分析纯属本人臆测,OS为Cent OS。内核为2.6.32-71.e16.i686。不过我开了下gentoo,发现gentoo的用户~目录下好像没有.bashrc文件、、、
(以上均为本人学习过程中的杂乱思绪,不免大量错误,不做任何参考。。)

2012.1.23