C++用PlaySoundexcel函数视频教程全集播出来的是系统错误的音效

怎么用PlaySound播放Wav的音频?
[问题点数:40分,结帖人u]
本版专家分:0
结帖率 100%
CSDN今日推荐
本版专家分:23712
本版专家分:54
本版专家分:0
本版专家分:0
本版专家分:0
本版专家分:292
本版专家分:292
本版专家分:0
本版专家分:292
本版专家分:369764
2017年 总版技术专家分年内排行榜第一
2014年 总版技术专家分年内排行榜第二
2013年 总版技术专家分年内排行榜第三
2012年 总版技术专家分年内排行榜第七
本版专家分:0
本版专家分:292
本版专家分:6183
本版专家分:6183
本版专家分:0
本版专家分:6183
本版专家分:0
匿名用户不能发表回复!
其他相关推荐这种方法只能打开.wma音频文件,MP3和WAV是打不开的。不过,你可以直接将手头上的MP3文件的后缀直接改成.wav,这样应该就可以了。
废话不说,说步骤。
1.首先是必须包含的头文件啦:
#include&windows.h&
#include &mmsystem.h&
#include&dsound.h&
#pragma comment(lib, "WINMM.LIB")
2.在你要播放/关闭音频的程序位置处添加:
mciSendString(TEXT("open 报警.wma alias mysong"), NULL, 0,NULL);//这一行是打开音频,你要播放音频肯定要先打开文件的,并将其命名为mysong.
//别忘了将文件放到文件夹里面哦,这样系统才可以直接根据文件名(相对路径)找到文件,否则是要用绝对路径的。
mciSendString(TEXT("play mysong repeat"), NULL, 0, NULL);//打开报警音
mciSendString(TEXT("close mysong"), NULL, 0, NULL);//关闭报警音
“报警.wma”是文件名,
3.如果TEXT被系统报错了,可能是字符集的问题。
要到项目属性里面改一个属性,步骤如下:
打开VS上面的“项目”———&“常规”———&“字符集“———&改成“使用多字节字符集”
这样就不会报错了。
PS:如果不报错的话,那么就别做这一步了。
做完这些,就可以在C++中直接用简单的代码播放.wav音频文件啦。
没有更多推荐了,直接上代码,如果有需要可以直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用了(注意将声道和频率与你自己的文件对应)。当然我自己也用VS2008写了个例子上传了,如果有需要下载地址如下:。
这份代码是打开文件截取一段数据然后播放的,可以轻松的经过加一条线程的方式改成网络传输的形式,但经过本人测试,因为没有缓存机制会有“哒哒”的噪声,也就是说这份代码在网络实时音频上的表现并不太好。为了解决这个问题,可以加上缓存机制,本人因为一开始用的是事件响应方式,所以一直困在这个框架里,不能很好的利用缓存的机制解决上面提到的问题,后来尝试了用回调函数的方式来响应数据播放完成的消息,问题就轻松的解决了。那部分的代码会在稍候放上去。
#include "stdafx.h"
#include &stdio.h&
#include &Windows.h&
#pragma comment(lib, "winmm.lib")
char buf[1024 * 1024 * 4];
int _tmain(int argc, _TCHAR* argv[]) {
FILE*//文件
WAVEFORMATEX
wfx.wFormatTag = WAVE_FORMAT_PCM;//设置波形声音的格式
wfx.nChannels = 1;//设置音频文件的通道数量
wfx.nSamplesPerSec = 8000;//设置每个声道播放和记录时的样本频率
wfx.nAvgBytesPerSec = 16000;//设置请求的平均数据传输率,单位byte/s。这个值对于创建缓冲大小是很有用的
wfx.nBlockAlign = 2;//以字节为单位设置块对齐
wfx.wBitsPerSample = 16;
wfx.cbSize = 0;//额外信息的大小
wait = CreateEvent(NULL, 0, 0, NULL);
waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD_PTR)wait, 0L, CALLBACK_EVENT);//打开一个给定的波形音频输出装置来进行回放
fopen_s(&thbgm, "paomo.pcm", "rb");
cnt = fread(buf, sizeof(char), 1024 * 1024 * 4, thbgm);//读取文件4M的数据到内存来进行播放,通过这个部分的修改,增加线程可变成网络音频数据的实时传输。当然如果希望播放完整的音频文件,也是要在这里稍微改一改
int dolenght = 0;
int playsize = 1024;
while (cnt) {//这一部分需要特别注意的是在循环回来之后不能花太长的时间去做读取数据之类的工作,不然在每个循环的间隙会有“哒哒”的噪音
wh.lpData = buf +
wh.dwBufferLength =
wh.dwFlags = 0L;
wh.dwLoops = 1L;
waveOutPrepareHeader(hwo, &wh, sizeof(WAVEHDR));//准备一个波形数据块用于播放
waveOutWrite(hwo, &wh, sizeof(WAVEHDR));//在音频媒体中播放第二个函数wh指定的数据
WaitForSingleObject(wait, INFINITE);//用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的INFINITE毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回
dolenght = dolenght +
cnt = cnt -
waveOutClose(hwo);
fclose(thbgm);
离写上面部分已经过了快一年,现在回看之前写的代码感觉略为坑爹,或许是进步了吧。之前说要把双缓存的代码放出来,哪知道后来忙别的项目去了,这部分就丢到一边,去老项目中提取代码感觉好烦一直没弄。在这一年中不少人发私信问我关于这部分代码如何写的事,没想到现在做音频的人还真不少呢。Ok,既然挖了坑就要填,今天乘着周末写了一个双缓存的Demo工程,代码如下:
#include &stdio.h&
#include &Windows.h&
#pragma comment(lib, "winmm.lib")
#define DATASIZE
//分次截取数据大小
//音频文件
void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance, DWORD dw1, DWORD dw2)//回调函数
switch (uMsg)
case WOM_DONE://上次缓存播放完成,触发该事件
LPWAVEHDR pWaveHeader = (LPWAVEHDR)dw1;
pWaveHeader-&dwBufferLength = fread(pWaveHeader-&lpData, 1, DATASIZE, pcmfile);;
waveOutPrepareHeader(hwo, pWaveHeader, sizeof(WAVEHDR));
waveOutWrite(hwo, pWaveHeader, sizeof(WAVEHDR));
void main()
WAVEFORMATEX
fopen_s(&pcmfile, "paomo.pcm", "rb");//打开文件
wfx.wFormatTag = WAVE_FORMAT_PCM;//设置波形声音的格式
wfx.nChannels = 1;//设置音频文件的通道数量
wfx.nSamplesPerSec = 8000;//设置每个声道播放和记录时的样本频率
wfx.nAvgBytesPerSec = 16000;//设置请求的平均数据传输率,单位byte/s。这个值对于创建缓冲大小是很有用的
wfx.nBlockAlign = 2;//以字节为单位设置块对齐
wfx.wBitsPerSample = 16;
wfx.cbSize = 0;//额外信息的大小
waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD)WaveCallback, 0L, CALLBACK_FUNCTION);//打开一个给定的波形音频输出装置来进行声音播放,方式为回调函数方式。如果是对话框程序,可以将第五个参数改为(DWORD)this,操作跟本Demo程序相似
wh1.dwLoops = 0L;//播放区一
wh1.lpData = new char[DATASIZE];
wh1.dwBufferLength = DATASIZE;
fread(wh1.lpData, 1, DATASIZE, pcmfile);
wh1.dwFlags = 0L;
waveOutPrepareHeader(hwo, &wh1, sizeof(WAVEHDR));//准备一个波形数据块用于播放
waveOutWrite(hwo, &wh1, sizeof(WAVEHDR));//在音频媒体中播放第二个参数指定的数据,也相当于开启一个播放区的意思
wh2.dwLoops = 0L;//播放区二,基本同上
wh2.lpData = new char[DATASIZE];
wh2.dwBufferLength = DATASIZE;
fread(wh2.lpData, 1, DATASIZE, pcmfile);
wh2.dwFlags = 0L;
waveOutPrepareHeader(hwo, &wh2, sizeof(WAVEHDR));
waveOutWrite(hwo, &wh2, sizeof(WAVEHDR));
while (wh1.dwBufferLength != 0 || wh2.dwBufferLength != 0)//如果文件还在没播放完则等待500ms
Sleep(500);
waveOutUnprepareHeader(hwo, &wh1, sizeof(WAVEHDR));//清理数据
waveOutUnprepareHeader(hwo, &wh2, sizeof(WAVEHDR));
delete []wh1.lpD
delete []wh2.lpD
fclose(pcmfile);//关闭文件
同上面一样,如果想要这个工程的可以到去下载。不过提醒下,本人已然抛弃了VS2008,直接用VS2013,如果还在用老平台的话要用还是要折腾一会的。
如何在C++中播放音频(几行代码搞定)
C++ 采集音频流(PCM裸流)实现录音功能
实现音频pcm数据播放(window平台)
最简单的视音频播放示例8:DirectSound播放PCM
PCM混音算法 C++实现 (包括归一化加权算法,时间片切割算法,幅值简单叠加算法)
C++ 调节PCM音频音量大小
C++ pcm音频裸流的压缩和解码
没有更多推荐了,逆向工程和函数调用的地址是_C / C++_编程语言_或代码
| 文章 >> 编程语言 >> C / C++
逆向工程和函数调用的地址是
{A}目录表下面是通过相互之间的关系进行分组的主题:这篇文章的目的,将会向您展示如何调用另一个程序通过自己的职能。本教程将被分解成一系列的步骤,与一般的例子,随后这方面的知识应用到实际的程序。本文主要使用调试器(OllyDbg的可免费下载)和Winject DLL的喷油器(免费提供网上下载callbin.zip)。 C编译器是需要的,如果你想编译的DLL的代码。编译测试应用程序,并试图上,将最有可能产生不同的结果,由于编译器设置,所以最好只使用在callbin.zip包括。原因是多方面的逆向工程过程中的内部函数的调用。例如,如果你见过任何游戏附加或"MODS??他们可能会使用这种技术调用一个进程的内部功能(​​游戏的),在屏幕上显示的文字。也许,你要扩展一个程序的热键功能。也许你在游戏中的功能调用"赢???无论如何,这种技术比这里提到的许多广泛应用。本教程推荐的唯一的东西,是一个体面的x86汇编知识知识,以及一些Win32 API的知识。让我们开始预先编写的应用程序,然后试图扭转工程师,在调用这个函数如何才能看到。我们来做一个简单的应用程序做一些算术,并输出值通过函数。下面是我们的测试应用程序:#undef UNICODE
#include &windows.h&
#include &stdio.h&
void mySecretFunction(int* param1, const char* param2,
DWORD param3, BYTE param4)
printf(&----------Function Entry----------\n&);
*param1 += 2008;
printf(&param1: %i\n&, *param1);
printf(&param2: %s\n&, param2);
param3 *= *param1;
printf(&param3 (param3 *= *param1): %i\n&, param3);
param4 = 0x90;
printf(&param4: %i\n&, param4);
printf(&----------Function Exit----------\n&);
int main(void)
int anArgument = 123;
if(GetAsyncKeyState(VK_F11) & 1)
mySecretFunction(&anArgument,
&This is the original text!&,
123456, 4);
else if(GetAsyncKeyState(VK_F1) & 1)
}这仅仅是一个功能,我很快写了接受四个参数(1,参考值3)。写你自己的和扭转的一大优点是,你已经知道要寻找什么。试图调用函数应用程序的地址,你没有源代码时,你应该准备做了很多额外的工作,因为它是绝对远不一样容易。我们现在要做的是逆向工程这个方案(包括在callbin.zip)正是这样一步一步的调试版本。为什么调试的构建,而不是一个释放与优化蓄客?我个人的理由是,它可能使分析有点调试器更容易,但对于这一点,这是相当不相关的。我也忘了这个想法,直到我完成全部文章(主要原因)。如果你看看这个方案建立的释放,这取决于编译器优化,mySecretFunction (...)可能成为与主联,它看起来截然不同,因为参数可能会存储在静态位置。另外,因为该功能有可能会被内联,试图调用它的地址将是一个相当无用的搜索。所以,让我们来分析,并开辟OllyDbg的。{A21}在OllyDbg的窗口,打F3,并找到TutExample.exe。开放后,你会看到此消息框弹出: {A22}您可以只需点击"确定"按钮继续;此警告弹出的调试版本(下VS2008 IDE,以供参考建)的性质。右击主窗口,并选择搜索- GT;所有intermodular电话,我们提出了这个新的窗口: 此窗口显示所有的功能,使我们的可执行文件调用。我们看到它从MSVCR90D.dll,GetAsyncKeyState调用printf从USER32.DLL,等等。通过使用此,我们可以找到这里我们主要()和mySecretFunction(???是首先,让我们与主(开始)和如何mySecretFunction(???获取所谓。双击GetAsyncKeyState职能之一,和OllyDbg的通过点击最上面的一个,将带你到的地方,他们被称为地址,OllyDbg的需要我们的东西,看起来像这样: {S2}既然我们的源代码,我们可以欺骗位,只需设置一个断点上GetAsyncKeyState(高亮行,然后按F2),因为我们知道它控制无论我们称之为mySecretFunction(??或没有,因为我们不希望不一定一步的功能和USER32.DLL如何实现,让我们的第一个GetAsyncKeyState函数断点并继续每行最多,包括第二GetAsyncKeyState函数上设置断点。大功告成之后,你应该有一些看起来像这样: {S3}
所以,让我们开始分析??命中F9(运行程序)。 OllyDbg的,应立即打的第一个断点,突出行。让我们打的F2线,由线,看看它从我们这里没有任何干扰。我们看到的程序来此行:{C},并采取跳。我们还应该注意,VK_F11关键代码0x7A,我们看到的是在栈上的权利推前调用GetAsyncKeyState。现在,我们可以分析这个函数是做什么,或更好,但它不这样做。让我们来看看这些被跳过的行:0041152C
68 40E20100
PUSH 1E240
68 EC574100
PUSH TutExamp.004157EC
LEA EAX,DWORD PTR SS:[EBP-8]
E8 D8FAFFFF
CALL TutExamp.
ADD ESP,10
JMP SHORT TutExamp.0041155F我们看到三个值入栈,然后一个地址装入EAX寄存器,然后将其压入堆栈。然后,我们调用一些功能,并修复堆栈后返回,并继续到我们的循环。这听起来很熟悉,而事实上是拆解的形式:mySecretFunction(&anArgument, &This is the original text!&, 123456, 4);这四个参数压入栈中以相反的顺序,因为LIFO(后进先出)堆栈功能,然后我们的功能是称为0x。所以,让我们的突出呼叫线路,并创下输入要带我们去我们的功能。我们看到它把我们带到这条线:
E9 A2030000
JMP TutExamp.这只是另一个跳转到0x。事实证明,我们的功能是不是在0x位置,但实际上是在位于0x。我们可以只敲回车再次在这条线,并在该地址的功能。一旦我们去0x,我们开始看到一些熟悉的东西,比如我们的函数入口,并退出printf语句。 0x是,我们希望在我们的程序调用,我们自定义的参数调用这个函数的地址。我们,虽然之前,我们至少应该分析发生了什么事情,在我们的函数,看看它是如何看起来拆解。他们将特别容易,因为他们是printf调用分离。另外,在查看源代码,你可以匹配正确的反汇编代码。{A23}注:大会懂行的人可以跳过这一部分,因为职能和解释非常简单。甚至分析此之前,如果我们看一下在函数的开始,我们看到:
MOV EBP,ESP
81EC C0000000
SUB ESP,0C0这是通常被称为拉开序幕,并设置一个堆栈帧传递的参数,局部变量,保存的寄存器,等。在这个函数结束时,你会看到一堆弹出寄存器:0041376E
81C4 C0000000
ADD ESP,0C0
CMP EBP,ESP
E8 CAD9FFFF
CALL TutExamp.
MOV ESP,EBP
POP EBP这就是所谓的尾声,恢复栈的状态,以便程序可以继续正常,一旦此功能完成。所有的参数,在这种情况下,将访问的东西添加到EBP(基址指针)。作为一个函数的参数传递的变量是[EBP的0x04的* N,其中N可以是1,2,3等。 [EBP 0x04的]是返回地址堆栈上,[EBP的0x08的第一个参数,[EBP 0x0C]第二个参数,等等,加上0x04的每次获得下一个参数。参数是[EBP的0x04的* N],局部变量将[EBP - 0x04的* N]。无论如何,拍背来分析的第一部分,取消引用param1和增加D8)。我已经评论的重要组成部分,并在大多数情况下,它是不言自明,给出了汇编语言的助记符知识。我不会去过多进入分析文本中的这些东西,因为图片中的评论正在发生的事情给一个明确的说明。让我们开始与PARAM1,工作的方式,以param4。我要解释什么是通过评论发生在拆装的重要线旁边。如果你想在调试器中的断点,你可以设置一个断点在这条线,然后,开始分析:
MOV EAX,DWORD PTR SS:[EBP+8],你可能会问为​​什么我们跳过以下几行:004113EB
CMP ESI,ESP
E8 50FDFFFF
CALL TutExamp.这是因为这些行不为任何目的,我们的分析,这些三线只是有干净后,调用printf。出发的:*param1 += 2008;
printf(&param1: %i\n&, *param1); {A24}在0x设置一个断点: {五}param3 *= *param1;
printf(&param3 (param3 *= *param1): %i\n&, param3);设置一个断点0x0041143D: {中六}param4 = 0x90;
printf(&param4: %i\n&, param4);在0x设置一个断点: {七}{A25}无论如何,现在我们已经分析了一切,和有一个良好的坚实的理解这件事情看起来和作品,我们可以继续前进。我们需要在一个特定的内存地址,在这个过程中以某种方式调用的函数。我们不能从我们自己的过程中,由于每个进程在自己的虚拟空间。比方说,这个代码编译和可执行文件运行secret.exe。让我们也说,我们不知道任何有关虚拟内存,和我们写了一个函数指向0x的应用程序,以为这是mySecretFunction (..).当我们试图调用该函数,我们肯定会得不到我们想要的结果(因在不同的地址空间的过程)。因此,我们需要做的是注入一个DLL。通过这样做,我们可以访问我们secret.exe的进程的内存空间。让我们来看看这个DLL的代码是什么样子。{A26}#include &windows.h&
DWORD WINAPI MyThread(LPVOID);
DWORD g_threadID;
HMODULE g_hM
void __stdcall CallFunction(int&, const char*, DWORD, BYTE);
INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
switch(Reason)
case DLL_PROCESS_ATTACH:
g_hModule = hDLL;
DisableThreadLibraryCalls(hDLL);
CreateThread(NULL, NULL, &MyThread, NULL, NULL, &g_threadID);
case DLL_THREAD_ATTACH:
case DLL_PROCESS_DETACH:
case DLL_THREAD_DETACH:
return TRUE;
DWORD WINAPI MyThread(LPVOID)
int myInt = 1;
while(true)
if(GetAsyncKeyState(VK_F2) & 1)
CallFunction(myInt, &My custom text&;, 1, 1);
else if(GetAsyncKeyState(VK_F3) &1)
Sleep(100);
FreeLibraryAndExitThread(g_hModule, 0);
void __stdcall CallFunction(int& param1, const char* param2, DWORD param3, BYTE param4)
typedef void (__stdcall *pFunctionAddress)(int&, const char*, DWORD, BYTE);
pFunctionAddress pMySecretFunction = (pFunctionAddress)(0x);
pMySecretFunction(param1, param2, param3, param4);
}出发的,它是非常简单的。我们创建了一个线程内的过程,我们这个DLL注入进去,并设立一个循环等待我们的按键。当我们按​​F2,我们应该调用我们的功能,在转弯的过程调用的内部函数。但是,我们可以通过我们自己的参数,而不是硬编码到原始文件的。我们CallFunction(??函数具有相同的mySecretFunction (???,的确切的宣言和中,我们成立了一个函数指针,我们选择__stdcall调用约定,因为它是最常见的一种C编译器的使用。需要,我们可以进一步分析我们拆解的可执行文件,并且看到堆栈是如何被清理,以推断出另一个为__cdecl是否正在使用,而不是我们正在做的是创建一个函数指针,以解决在可执行文件,这是地址,我们发现早期mySecretFunction (???.一旦我们找到它,我们呼吁我们的自定义参数。0x所以,让我们的测试,看看从一开始就运行编译后的代码本教程中,我们看到这样的: {S8}这看起来正常的,而且是完全预计从程序的行为。现在,让我们的注入我们的DLL,并看看会发生什么,当我们按F2。 {S9}我们可以清楚地看到的东西是不同的。但是,这是我们所期望的吗?让我们来看看我们的参数,看看他们应根据mySecretFunction (???.代码1,我们通过"我的自定义文本??1,1的功能。1 = 2008 = 2009(正确)。 "我自定义的文本??输出(正确)1 *= 2009 = 2009(正确)。Param4设置等于0x90(144十进制,正确)。看起来一切都工作正常,我们可以继续按F11得到原有的功能,我们可以按F2和得到我们的自定义,但很显然,我们看到的东西是不同的,而且,我们可以选择用我们自己的参数调用这个函数。{A27}一个重要的事情要注意的是,这是很重要的是要小心的数据类型。你应该总是通过每一块一步,并看到它的输出。后来,如果我们以某种错误,而不是一个const char * INT,param2的,我们会得到一些意想不到的结果,甚至由于有记忆问题的程序崩溃。查看相对EBP的地址,我们将会看到,param2的持有字符,而PARAM1,参数3,和param4持有某种类型的数字。让我们来看看某些情况下,我们不一定宣布原有的功能相同的参数类型,看看会发生什么。我们应该探讨有一些变化,即:不使用param2的常量字符*。为param1/3/4使用不同数量的数据类型。让我们先从第一种情况下。从顶部底部DLL中的代码,这里的线路和我们改变他们。void __stdcall CallFunction(int&, int, DWORD, BYTE);
CallFunction(myInt, 12345, 1, 1);
void __stdcall CallFunction(int& param1, int param2, DWORD param3, BYTE param4)
typedef void (__stdcall *pFunctionAddress)(int&, int, DWORD, BYTE);因此,这些变化后,我们的新的DLL注入的过程,我们可以按F11,并迎来一个熟悉的消息。然而,当我们按下F2键,我们看到程序崩溃有权在输出param2的点。真的没有多说,这除了要小心,和适当的数据类型的工作,当它涉及到两个不同的东西,如const char *和数值类型。如果我们改变其他参数之一,那么会发生什么?请问程序仍然崩溃,如果我们要改变的DWORD字节的第三个参数?简短的回答是"没有?? ,这其中至少不会(你可以自己尝试)。然而,我们从我们的一些参数得到意想不到的输出,这使得调用函数没用,如果它不给我们,我们所期望的排序。我们的程序没有崩溃的问题并不普遍;的,而比例外。程序可能会或可能不会崩溃,这取决于是什么参数。我们刚刚加入,multiplyin,并输出;别人可能不那么友好的字节类型,而不是DWORD值,或同样。{A28}现在,在一个实际的例子,我们不知道源代码,我们需要做一些猜测工作。一样,因为我不喜欢给扫雷或标准的Windows游戏"真实的吗??的例子,如简单的程序,我可以不认为任何其他的使用,作为常见的台式机,因为这些游戏,并在此技术可以用来实现真正有用的东西。我的现实世界的例子将一个大型应用程序或游戏很多功能调用其功能可以产生一些很酷的妆效。不过,我会想象太多值得商榷的合法性,也违反了某些CodeProject上的文章提交指南。无论如何,让我们开始我们的扫雷游戏,在这里我们可以应用此技术。我们的窗口: {S10}所以,在这里我们会运用这种技术呢?就个人而言,我想,这将会是很好,如果我们有一个热键,为我们赢得比赛。让我们去给它,然后,但是,在我们开始之前,我们应该奠定了正是我们将要做的事。我们的目标是:查找扫雷使用的功能,赢得比赛。看什么参数,以及它是如何工作的。写一个DLL,我们可以注入,并设置一个热键调用此功能,为我们。{A29}但是,怎么办,我们发现这个神秘功能?有很多方式,从这里去,每个不同难度的。这个问题,我的做法是怎么看游戏的行为,当你赢得一场比赛。我注意到,如果我的声音启用,游戏会播放声音时,我赢了一场比赛(或时钟打勾,或我打了炸弹)。我们可以使用此信息和跟踪API播放声音,然后向后,我们可以临到你赢的比赛时执行的功能。因此,打开游戏在OllyDbg中,并按下F9(运行程序)。这样做后,你可以打CTRL一个让OllyDbg的分析一些代码。我们正在寻找一个API播放声音的话,右击主窗口,去搜索- GT;所有Intermodular调用。您将会看到一个漂亮的大名单,大于在示例程序中的一个。点击"的目的地是哪里??"选项卡这些API名称按字母顺序排序。有吨的API,而是应该抓住我们的眼球。 {S11} PlaySoundW听起来很有趣。根据MSDN,这里的PlaySound API: PlaySound函数起着指定一个给定的文件名,资源,或系统事件声音。 (系统事件可能与一个在注册表或Win.ini文件中的声音。)BOOL PlaySound(
LPCTSTR pszSound,
HMODULE hmod,
DWORD fdwSound
);这绝对是我们所希望的,所以让所有这三个设置一个断点。这样做后,我们应该回去的主要扫雷窗口,并点击开始游戏瓷砖。紧接着,我们应该打一个断点:
CALL DWORD PTR DS:[&&WINMM.PlaySoundW&]
如果我们打F9继续运行这个程序,我们将看到,这个特定的一个被称为定时器每次增加1。如果我们把断点并继续,我们看到这个API不被调用了定时器。然而,它也不会被调用时,你赢得或输掉一场比赛。这意味着该特定之一就是负责所有三个工作向后,我们可以看到什么是调用它。 {S12}我们可以看到,我们已经有了从0xx跳转到这个函数。所以,让我们上设置断点,看看是怎么回事。
PUSH 40005
|. FF35 305B0001
PUSH DWORD PTR DS:[1005B30]
|. 68 B2010000
JMP SHORT WINMINE.
PUSH 40005
|. FF35 305B0001
PUSH DWORD PTR DS:[1005B30]
68 B1010000
JMP SHORT WINMINE.我们可以看到,这两个部分是在堆栈上推三个参数,然后调用PlaySoundW。如果我们从早期的注意,滴答作响的噪音LPCTSTR pszSound参数0x1B0。在这里,我们有0x1B2和0x1B1。只要使用逻辑,可以推测,这两个对应的爆炸声和胜利的声音。但是,哪一个?这就是我们要测试。让我们设置一个断点,并在每一个看到。我们注意到,如果我们开始一个新游戏,碰巧来了炸弹后,我们得到了一个断点:
|. 68 B2010000
PUSH 1B2如果我们赢了一场比赛,0x1B1推。因此,我们必须0x1B2的爆炸声,0x1B1胜利的声音,滴答声0x1B0。因此,代码的关键部分是这样的:
PUSH 40005
|. FF35 305B0001
PUSH DWORD PTR DS:[1005B30]
68 B1010000
JMP SHORT WINMINE.现在,向后再次,我们要找到什么叫。如果我们点击0x上,我们看到在主窗口: {S13}注:我们也可以右击命令,去寻找- GT;选定的命令(CTRL R)。再次倒退0x010038FE和调查周围有什么,我们来到这个代码块时,这个整体功能开始0x010038ED:010038ED
/$ 833D B8560001 &CMP DWORD PTR DS:[
JNZ SHORT WINMINE.0100393D
|. 8B4424 04
MOV EAX,DWORD PTR SS:[ESP+4]
JE SHORT WINMINE.
JE SHORT WINMINE.
JNZ SHORT WINMINE.0100393D我们可以看到,在10056B8的价值得到与3相比,我们可以推断,作为一个switch语句的3例。 [ESP 4]的值移入EAX,然后我们看到它是什么,并采取相应的行动。我们还没有,但但似乎我们正在接近。让我们去的功能,看看什么叫。选择的路线,按Ctrl R来看看有什么调用此。 {S14}让我们在所有三个设置一个断点,并开始一个新游戏。随即,我们应该打这个:0100382B
|. E8 BD000000
CALL WINMINE.010038ED由于我们甚至还没有开始打还,让仅赢了,我们应该删除断点,继续前进。一两秒钟后,我们继续,我们打这一行:
|. E8 E6080000
CALL WINMINE.010038ED这是不是我们想要的或者。我们已经有了,它的范围缩小到现在。010034CF
CALL WINMINE.010038ED环顾了一下实验,我们可以看到,0x010034CF被称为当我们赢得或输掉一场比赛。现在,我们只需要进行区分,并找出是什么决定我们是否输赢。让我们看看在此作为一个整体的功能:0100347C
&AND DWORD PTR DS:[1005164],0
|. 8B7424 08
MOV ESI,DWORD PTR SS:[ESP+8]
XOR EAX,EAX
TEST ESI,ESI
MOV DWORD PTR DS:[1005160],EAX
|. E8 77F4FFFF
CALL WINMINE.
XOR EAX,EAX
TEST ESI,ESI
|. 8D00&LEA EAX,DWORD PTR DS:[EAX*4+A]
|. E8 D0FAFFFF
CALL WINMINE.01002F80
TEST ESI,ESI
JE SHORT WINMINE.
MOV EAX,DWORD PTR DS:[1005194]
TEST EAX,EAX
JE SHORT WINMINE.
|. E8 A5FFFFFF
CALL WINMINE.0100346A
MOV EAX,ESI
SBB EAX,EAX
|. 83C0 03
CALL WINMINE.010038ED
TEST ESI,ESI
&MOV DWORD PTR DS:[1005000],10
JE SHORT WINMINE.0100350F
|. 66:A1 A0560001 MOV AX,WORD PTR DS:[10056A0]
|. 66:3D 0300
JE SHORT WINMINE.0100350F
|. 8B0D 9C570001
MOV ECX,DWORD PTR DS:[100579C]
MOVZX EAX,AX
|. 8D0485 CC56000&LEA EAX,DWORD PTR DS:[EAX*4+10056CC]
CMP ECX,DWORD PTR DS:[EAX]
JGE SHORT WINMINE.0100350F
MOV DWORD PTR DS:[EAX],ECX
|. E8 77E6FFFF
CALL WINMINE.01001B81
|. E8 9BE6FFFF
CALL WINMINE.01001BAA
\& C2 0400
RETN 4让我们设置一个断点的功能开始,在每一行,一路攀升到return语句结束。由于这个函数被调用时,你赢了,当你失去,你就可以开始检查它的哪些部分被跳过,当这些条件发生。所有这些线路上设置一个断点,并失去了游戏后,我们发现,这些生产线将被跳过。
MOV EAX,DWORD PTR DS:[1005194]
TEST EAX,EAX
JE SHORT WINMINE.
|. E8 A5FFFFFF
CALL WINMINE.0100346A我们还发现,当你失去了要执行的函数的最后一个语句是:
JE SHORT WINMINE.0100350F现在,看看会发生什么当你赢了。我们发现功能得到全部执行。注意:如果你在调试器中跟着你的游戏在此行停止:010034ED
JE SHORT WINMINE.0100350F这是因为在此之后的行检查,看你是否符合资格的高评分表。那么,是什么差别,决定了跳跃?我们来到这几行:
TEST ESI,ESI
JE SHORT WINMINE.
在这里,我们测试,看看如果ESI是0,而如果这样,我们采取跳,跳过一个赢得游戏,超过部分处理。换句话说,如果ESI是0,那么我们就失去了。 ESI的价值是什么,当我们赢了,我们可以简单地检查它在OllyDbg中的价值,在该行。 {S15}我们可以看到,当我们赢的ESI的值是1。因此,如果是ESI设置?如果我们仔细的功能,我们可以看到,附近的开始,是这一行:到这个函数的第一个参数是移动到ESI。为什么ESP的,而不是在原来的例子EBP的?这是因为此功能不成立一个像其他的堆栈帧,这样的参数是通过ESP,EBP的而不是访问。我们看到,ESP的最高值是8,这个函数返回4,因此我们可以推断出,只需要一个参数。我们甚至可以核实检查0x0100347C和看到只有一个推动调用前声明。我们已经实现了两个,三个我们原来的目标,所以现在,剩下的就是只写我们的DLL,使一个热键调用这个函数作为参数与1。因为我们正在进入一个32位寄存器参数,我们可以将其作为我们的DLL类型为DWORD(尽管在拆装DWORD PTR)。有兴趣在任何情况下是一个全功能的描述,下面是我的笔记,从加强和迅速扫视了会发生什么。
{A30}{A31}在这里,我们可以使用原有的功能的DLL的模板。只是一些琐碎的事情,改变周围。新的代码如下:#include &windows.h&
DWORD WINAPI MyThread(LPVOID);
DWORD g_threadID;
HMODULE g_hM
void __stdcall CallFunction(void);
INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
switch(Reason)
case DLL_PROCESS_ATTACH:
g_hModule = hDLL;
DisableThreadLibraryCalls(hDLL);
CreateThread(NULL, NULL, &MyThread, NULL, NULL, &g_threadID);
case DLL_THREAD_ATTACH:
case DLL_PROCESS_DETACH:
case DLL_THREAD_DETACH:
return TRUE;
DWORD WINAPI MyThread(LPVOID)
while(true)
if(GetAsyncKeyState(VK_F3) & 1)
CallFunction();
else if(GetAsyncKeyState(VK_F4) & 1)
Sleep(100);
FreeLibraryAndExitThread(g_hModule, 0);
void __stdcall CallFunction(void)
typedef void (__stdcall *pFunctionAddress)(DWORD);
pFunctionAddress pWinFunction = (pFunctionAddress)(0x0100347C);
pWinFunction(1);
}让我们对其进行测试,好措施。开始了一个新的扫雷的实例,并注入DLL。的瓷砖上,点击开始游戏,然后按F3热键。结果呢?希望类似这样的东西。 {S17}你会发现,全板没有得到显露,当你赢了,但可以作为行使读者:-)留下。{A32}{A33}{A34}{A35}{A36}日 - 提交文章。
关于作者:
中国我是一名编程爱好者,谢谢orcode.com为我们提供一个学习和分享的平台。有什么问题。可以就本内容回复,我看到时。会尽量回复的。
评论会员:
时间:?我可以使用MS的Detour钩子函数我已经尝试过,但没有成功。
void outtext( char* text, int i)
printf("%d",i);
printf(text);
int _tmain(int argc, _TCHAR* argv[])
int i = 0;
outtext("hello\n", i);
typedef void ( __stdcall *pFunc)(char*, int);
pFunc OutText = (pFunc)(0x);
void __stdcall MyOutText(char* text, int i)
printf("%d", i);
printf("good\n");
DisableThreadLibraryCalls(hDLL);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetouAttach(&(PVOID&)OutText, MyOutText);
DetourTransactionCommit();
如果它的工作吗?我用迂回3.0; 其他问题挂钩,没有WINAPI工程 修改11月25日'11 评论会员:
时间:!感谢分享这个评论会员:
时间:我这个新手。 我想知道如何测试应用程序的DLL注入。我有写另一个用于该计划的吗​​? {S18} 评论会员:
时间:。真正的好文章,我读了逆向工程至今评论会员:
时间:酷评论会员:
时间:你能给我学习汇编语言的一些技巧{ BR}评论会员:
时间: http://www.hex-rays.com/idapro/
检查出的图形,
我用这个扭转一个专有的数据库导出方案。我的技能是太有限了已完成从产品的图形没有大规模援助评论会员:
时间:我喜欢你的屏幕分辨率{S19}
亚历克斯伟大的文章!如果有超过5个,我想给它评论会员:
时间:垃圾邮件删除评论会员:
时间:我学到了很多从这个。顺便说一句,我在宾夕法尼亚州立大学的一个分校前数学教师,目前的软件开发人员评论会员:
时间:好文章。感谢您的贡献。
的问候,KOTI 评论会员:
时间:你应该到目标应用程序的消息队列挂钩,以检查是否热键是不是按了。创建一个新线程是浪费CPU(尤其是与你的"无眠"的实施)和慢更不准确。除此之外,好文章评论会员:
时间:我知道我被遗忘的东西 - 感谢你提醒我有关睡眠。我会尽力更新本文中的代码和下载,以反映此。关于挂接到消息队列中,你的意思是我应该成立一个过程中的具体键盘钩子,并通过检测KeyboardProc热键?如果是这样,然后我"之类的"避免前往这条路的目的,因为我不想关闭主题文章的目的也得到/写说明一个单独的应用程序注入DLL,并设置钩。{ BR}评论会员:
时间:我的意思是挂钩的WndProc或API PeekMessageA或PostMessageA。从那里你可以检查,如果用户按下了键,你作为热键使用。只是检查是浪费的CPU仍然较慢,比挂接在消息队列(目标应用程序的)的地方更低效的另一个线程评论会员:
时间:这似乎像一个非常有趣的方法。在过去,我已经做了一些API的挂钩与MS绕行,但从来没有想过要做到这一点,以检查为热键。的意见评论会员:
时间:喜亚历克斯,
伟大的工作!有我呢!
{A38},安全研究员作者的"API钩子透露,"{A39} AntiHook 3.0,HookTool.NET SDK V3.6:{A40} 评论会员:
时间:了解,奥利是放大器;^%$#功能强大。书签。 不会枯燥看到越来越多的喜欢这篇文章。
,-=艾伯特=- 评论会员:
时间:,在这篇文章中,有没有任何价值,是面试的无人驾驶飞机
另一方面,它引起我一些思考和一些进程的运作进一步了解。
这使得一个真正有价值的贡献。
彼得WASSER 评论会员:
时间:亚历克斯 - 这是一个令人耳目一新的变化,批准喜欢这篇文章,并释放它一般CP阅读人口。优秀的文章,我为你的未来寄予厚望。从我5。
德雅查看 - 你看到这篇文章之前的感觉
&桌面&网页开发&移动开发&数据库&多媒体&编程语言&平台,框架和库&编程通用&图形/设计&开发周期&一般阅读&第三方产品&作者资源&其他
快速解答标签
价值作最多

我要回帖

更多关于 if函数怎么写多个条件 的文章

 

随机推荐