Wine学习.docx
《Wine学习.docx》由会员分享,可在线阅读,更多相关《Wine学习.docx(33页珍藏版)》请在冰点文库上搜索。
Wine学习
1、Wine
1、wine实现了大多数的windowsAPI,集成了winedbg
2、windowsAPI
1)kernel32.dll
允许一个W-process作为debugger去执行另一个W-process,作为debuggee,包括设置breakpoint,单步执行等等
2)DBGHELP.DLL
让一个debbuger从任意模块查找符号和类型
3、异常解决
怎么根据下面信息查找crash原因
Unhandledexception:
pagefaultonwriteaccessto0x00000000in32-bitcode(0x0043369e).
Registerdump:
CS:
0023SS:
002bDS:
002bES:
002bFS:
0063GS:
006b
EIP:
0043369eESP:
0b3ee90cEBP:
0b3ee938EFLAGS:
00010246(R---IZ--P-)
EAX:
00000072EBX:
7b8acff4ECX:
00000000EDX:
6f727265
ESI:
7ba3b37cEDI:
7ffa0000
Stackdump:
0x0b3ee90c:
7b82ced8000000007ba3b3487b884401
0x0b3ee91c:
7b883cdc00000008000000007bc36e7b
0x0b3ee92c:
7b8acff47b82ceb97b8acff40b3eea18
0x0b3ee93c:
7b82ce82000000000000000000000000
0x0b3ee94c:
000000000b3ee96870d7ed7b70c50000
0x0b3ee95c:
000000000b3eea407b87fd407b82d0d0
Backtrace:
=>00x0043369einelementclient(+0x3369e)(0x0b3ee938)
10x7b82ce82CONSOLE_SendEventThread+0xe1(pmt=0x0(nil))[/usr/src/debug/wine-1.5.14/dlls/kernel32/console.c:
1989]inkernel32(0x0b3eea18)
20x7bc76320call_thread_func_wrapper+0xb()inntdll(0x0b3eea28)
30x7bc7916ecall_thread_func+0x7d(entry=0x7b82cda0,arg=0x0(nil),frame=0xb3eeb18)[/usr/src/debug/wine-1.5.14/dlls/ntdll/signal_i386.c:
2522]inntdll(0x0b3eeaf8)
40x7bc762feRtlRaiseException+0x21()inntdll(0x0b3eeb18)
50x7bc7f3dastart_thread+0xe9(info=0x7ffa0fb8)[/usr/src/debug/wine-1.5.14/dlls/ntdll/thread.c:
408]inntdll(0x0b3ef368)
60xf7597adfstart_thread+0xce()inlibpthread.so.0(0x0b3ef468)
0x0043369e:
movl %edx,0x0(%ecx)
Modules:
ModuleAddressDebuginfoName(143modules)
PE340000-3af000Deferredspeedtreert
PE71930000-719b8000Deferredshdoclc
PE78130000-781cb000Deferredmsvcr80
ELF79afb000-7b800000Deferredlibnvidia-glcore.so.304.51
ELF7b800000-7ba3d000Dwarfkernel32
\-PE7b810000-7ba3d000\kernel32
ELF7bc00000-7bcd5000Dwarfntdll
\-PE7bc10000-7bcd5000\ntdll
ELF7bf00000-7bf04000Deferred
ELF7c288000-7c400000Deferredlibvorbisenc.so.2
PE7c420000-7c4a7000Deferredmsvcp80
ELF7c56d000-7c5b6000Deferreddinput
Threads:
processtidprio(allid:
sareinhex)
00000008(D)C:
\PerfectWorldEntertainment\PerfectWorldInternational\element\elementclient.exe
000000310<==
0000003515
000000120
000000210
000000450
000000440
000000430
0000003815
000000370
0000003615
000000340
000000330
000000320
000000270
000000090
0000000eservices.exe
0000000b0
000000200
000000170
000000100
0000000f0
下面信息的含义:
000d:
Calladvapi32.RegOpenKeyExW(00000090,7eb94da0L"Patterns",00000000,00020019,0033f968)ret=7eb39af8
000d:
线程id
advapi32:
被调用模块
RegOpenKeyExW:
被调用函数
后面几个都是参数
ret:
返回地址
4、Usefulmemoryaddress
1)32位
linux:
0x080000000x004000000x40000000
2)16位(增强模式):
segment:
offset
segment如果最低三比特位都是1,就是一个selector,如果最低三笔特除了最低位外都是1,可能是全局内存
0x1f7(0x40320000,0x0000ffff,r-x):
分别是基地址,最大偏移,访问权限r-x表示可读可执行
实际地址:
selector基地址+offset
3)16位(标准模式):
segment:
offset
segment和offset可以是0~0xffff
实际地址:
segment×16+offset
5、配置
1)配置debuger
[MACHINE\\Software\\Microsoft\\WindowsNT\\CurrentVersion\\AeDebug]957636538
"Auto"=dword:
00000001
"Debugger"="winedbg%ld%ld"
2)配置winedbg
[HKCU\\Software\\Wine\\WineDbg]
BreakAllThreadsStartupTRUE:
所有线程停止FALSE:
第一个线程停止
BreakOnCritSectTimeOutTRUE:
在临界区超时5分钟停止FALSE:
不停止
BreakOnAttach
BreakOnFirstChance
一个异常产生两个debug事件,或者说两次chance
firstchance:
发生异常之后传递给debugger,debugger要么继续执行(cont),要么交给exceptionhandlerchain(pass)
lastchance:
如果没有exceptionhandler处理异常,会再次传递给debugger,这一次不能pass
TRUE:
两次机会都会处理FALSE:
仅仅进入lastchance
AlwaysShowThunkTRUE:
根据名称显示所有thunksFALSE:
3)+relay行为配置
可能输出会很多,但可以进行设置
[HKCU\\Software\\Wine\\Debug]
RelayExclude列出不需要的输出
RelayInclude仅输出列出的输出
怎么知道哪些输出是不需要的?
WINEDEBUG=+relaywineappname.exe&>relay.log
awk-F'(''{print$1}'2、WineDbg
1、WineDbg表达式
同C格式总体相同,有少量差异。
1)表达式名称里可以用!
2)转换操作时结构体或联合体都需要带struct或union关键字
winedbg特殊变量:
$ThreadId即W-threadid
$ProcessId即W-processid
所有CPU寄存器值也是变量
2、WineDbg命令
Misccommands
NO.
command
Details
1
abort
abortthedebbuger
2
quit
Quitthedebbuger
3
AttachW-processID
附加到另一个进程
4
Detach
分离进程
5
help
6
helpinfo
Flowcontrolcommands
NO.
command
Details
1
cont,c
继续执行
2
pass
传递异常给filterchain
3
step,s
单步,进入函数调用
4
stepi,si
单个指令
5
next,n
单步,不进入函数
6
nexti,ni
单个指令,不进入调用
7
finish,f
执行直到当前函数退出
Breakpoints,watchpoints
NO.
command
Details
1
enableN
激活break|watchpointN
2
disableN
禁用break|watchpointN
3
deleteN
删除break|watchpointN
4
condN
移除任何到break|watchpointN的条件
5
condNexpr
按表达式设置breakpointN触发条件
6
break*N
增加breakpointN(N为地址)
7
breakid
增加breakpoint符号id的地址?
?
8
breakidN
符号id的第N行?
?
9
breakN
当前源文件的第N行
10
break
当前$PC地址设置breakpoint
11
watch*N
观察指令,*N为地址
12
watchid
符号id的地址
13
infobreak
列出所有break|watchpoint
Stackmanipulation
NO.
command
Details
1
bt
打印当前线程栈调用
2
btN
打印线程ID为N的线程栈调用
3
up
往上走1frame?
?
4
upN
往上走Nframe
5
dn
往下走1frame
6
dnN
7
frameN
执行直到当前函数退出
8
infolocal
局部变量
Directory&sourcefilemanipulation
NO.
command
Details
1
showdir
打印源文件查找目录
2
dirpathname
增加路径到查找目录列表
3
dir
删除查找目录列表
4
symbolfilepathnamme
加载外部符号定义
5
symbolfilepathnameN
同上,但是有个偏移地址N
6
list/-/N/file:
N
默认列出10行代码,-向后列出
7
listid
列出函数id处的10行代码
8
list*N
列出地址N处10行代码
9
listN1,N2
列出从N1行到N2行的源码
10
listfile:
N1,N2
列出文件file从N1行到N2行的源码
Displaying
NO.
command
Details
1
infodisplay
?
?
2
display
3
displayexpr
4
displaylfmtexpr
按格式输出
5
deldisplayN,undisplayN
删除display
Disassembly
NO.
command
Details
1
disas
反汇编
2
disasexpr
指定地址出汇编代码
3
disasexpr,expr
两个地址之间的汇编
Memory(reading,writing,typing)
NO.
command
Details
1
xexpr/lfmtexpr
显示地址出的值,格式?
?
2
printexpr/lfmtexpr
打印表达式的值
3
setlval=expr
设置变量
4
whatisexpr
打印C类型的表达式
5
set!
symbol_pickerinteractive
打印的时候由用户决定选那个符号
6
set!
symbol_pickerscopedb
优先局部符号,然后才是全局的
vfmt可以是letter或countletter?
?
sasciistring
uutf16string
i指令
x32-bit无符号16进制整数
d32-bit无符号10进制整数
w16-bit无符号16进制整数
c可打印字符,0x20~0x70实际是可打印的
b8-bit无符号16进制整数
gGUID
InformationonWineinternals
NO.
command
Details
1
infoclass
列举所有窗口类
2
infoclassid
关于窗口类id的信息
3
infoshare
列举所有动态库,so或dll
4
infoshareN
地址N的模块信息
5
inforegs
CPU寄存器信息
6
infoall-regs
CPU和浮点寄存器
7
infosegmentN
在segmentN的信息,仅i386
8
infosegment
所有segment,仅i386
9
infostack
栈信息
10
infomap
debbuger的虚拟映射
11
infomapN
wpidN的虚拟映射
12
infowndN
打印窗口N的信息
13
infownd
列举从桌面开始的所有窗口层次
14
infoprocess
列举wine回话中所有w-processes
15
infothread
列举所有w-threads
16
infoexception
异常信息
Debugchannels
NO.
command
Details
1
set+warn
打开warnchannel
2
set+channel
打开warn/fixme/err/trace
3
set-channel
关闭上述channel
4
set-fixme
关闭fixme
3、其他Debuggers
1.GDB模式
winedbg是一个远程gdb监视器,增加--gdb即可激活gdb模式。
gdb和winegdb的区别
winegdb掌控一个进程的所有线程,可以处理所有线程断点。
gdb只能对单个线程进行调试。
Winegdb支持stabs(standardUnixformat)和C,CodeView,.DBG(Microsoft).gdb支持stabs和DwarfII
2.DDD
如下命令:
winedbg--gdb--no-start*.exeoptionalparam
然后把输出:
targetremotelocalhost:
12345粘贴到ddd即可运行
3.kdbg
其他同ddd,运行时在kdbg终端运行:
kdbg-rlocalhost:
12345wine
4、调试技巧
1、debugingclasses
FIXME
ERR
WARN
TRACE
MESSAGE
2、debuggingchannels
每个组件都会有一个channel
设置方法:
WINE_DEFAULT_DEBUG_CHANNEL(xxx);
如果要有多个channel,则增加多个名称不同即可。
使用的时候,需要使用类似FIXME_(xxx)(fmt,...);此时FIXME(fmt,...);指向第一个声明channel
TRACE_ONWARN_ONERR_ONFIXME_ON用来判断是否打开了
3、一些有用的函数
1)debugres
LPSTRdebugres(constvoid*id);
id:
资源id指针
返回:
字符串类型,格式化字符串
2)debugstr_[aw]n
处理某些NULL,控制字符或太长,或需要转换成ascii,都可以使用这些函数处理
4、修改调试输出
第一种方法:
使用winedbg命令
第二种方法:
通过taskmgr修改
第三种方法:
创建pipe和运行WINEDEBUG
mknode/tmp/debug_pipep
WINEDEBUG=+relay,+snoopwinesetup.exe&>/tmp/debug_pipe
cat/tmp/debug_pipe
WINEDEBUG格式:
WINEDEBUG=[yyy]#xxx[,[yyy1]#xxx1]*
yyy:
trace,debug,warn,fixme,err等,fixme和err默认是激活的,trace和warn默认是没激活的
#:
+或-
xxx:
channel,all表示所有channel
可以用,隔开添加多个
如果使用MessageBox,则
WINEDEBUG=+relaywineprogram_name&>relmsg
5、风格上的一些注意
输出格式:
class:
channel:
functionmessage
6、一些其他技术
i386系统,栈是4字节,小端,地址向下增长,栈指针存放在esp寄存器,指向栈内存最后一次push进去的数据的地址。
可以表示为:
push操作:
*(--esp)=p;pop操作:
p=*(esp++);
额外补充:
1)调用协议常用场合
__stdcall:
WindowsAPI默认的函数调用协议。
__cdecl:
C/C++默认的函数调用协议。
__fastcall:
适用于对性能要求较高的场合。
2)函数参数入栈方式
3)
__stdcall:
函数参数由右向左入栈。
__cdecl:
函数参数由右向左入栈。
__fastcall:
从左开始不大于4字节的参数放入CPU的ECX和EDX寄存器,其余参数从右向左入栈。
问题一:
__fastcall在寄存器中放入不大于4字节的参数,故性能较高,适用于需要高性能的场合。
4)栈内数据清除方式
__stdcall:
函数调用结束后由被调用函数清除栈内数据。
__cdecl:
函数调用结束后由函数调用者清除栈内数据。
__fastcall:
函数调用结束后由被调用函数清除栈内数据。
问题一:
不同编译器设定的栈结构不尽相同,跨开发平台时由函数调用者清除栈内数据不可行。
问题二:
某些函数的参数是可变的,如printf函数,这样的函数只能由函数调用者清除栈内数据。
问题三:
由调用者清除栈内数据时,每次调用都包含清除栈内数据的代码,故可执行文件较大。
5)C语言编译器函数名称修饰规则
__stdcall:
编译后,函数名被修饰为“_functionname@number”。
__cdecl:
编译后,函数名被修饰为“_functionname”。
__fastcall:
编译后,函数名给修饰为“@functionname@nmuber”。
注:
“functionname”为函数名,“number”为参数字节数。
注:
函数实现和函数定义时如果使用了不同的函数调用协议,则无法实现函数调用。
6)C++语言编译器函数名称修饰规则
__stdcall:
编译后,函数名被修饰为“?
functionname@@YG******@Z”。
__cdecl:
编译后,函数名被修饰为“?
functionname@@YA******@Z”。
__fastcall:
编译后,函数名被修饰为“?
functionname@@YI******@Z”。
注:
“******”为函数返回值类型和参数类型表。
注:
函数实现和函数定义时如果使用了不同的函数调用协议,则无法实现函数调用。
C语言和C++语言间如果不进行特殊处理,也无法实现函数的互相调用。
stdcall调用:
从右往左一次将参数push进栈。
例如:
function(20,30,40,50);为
push50
push40
push30
push20
//此时栈的状况:
othervariable
50
40
30
20<---esp指向这里
callfunction
//此时
othervariable<---esp指向这里
但是这里有个问题是调用函数如何知道被调用函数有多少个参数
有两种方法:
第一,记录栈偏移 第二,
DLLs
内存管理
每个进程有4GB空间
虚拟映射,页面可以进行映射,如果访问未映射内存,报告0x0005错误。
7、利用堆栈信息调试
CS:
0023SS:
002bDS:
002bES:
002bFS:
0063GS:
006b
EIP:
00355ab4ESP:
0033df70EBP:
0033f1e8EFLAGS:
0021020