原理和PC端游戏的方法类似,但是分析破解难度会比PC高,因为动态调试只能用IDA,而且很麻烦,每次加载速度很慢,一般都是静态分析,另外是ARM的指令集。
1、编写程序A
用于启动目标程序,并且要完成模块注入,和拦截函数调用地址的替换, 这里还实现了一些比如SQLite数据库数据预处理的一些功能,包括AES密码加密。
void writedword(uint32_t offset, uint32_t value) { DWORD n; if (!WriteProcessMemory(_pid, (void*)offset, (void*)&value, sizeof(uint32_t), &n)) //throw "invalid pointer"; printf("proc %08lx.word= %08x\n", offset, value); } BOOL isExist(LPCTSTR processName) { HANDLE hHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS|TH32CS_SNAPNOHEAPS, 0); if (hHandle == INVALID_HANDLE_VALUE) return FALSE; BOOL ret = FALSE; PROCESSENTRY32 entry; entry.dwSize= sizeof(PROCESSENTRY32); if (Process32First( hHandle , &entry) ) { do { if (wcscmp( processName , entry.szExeFile)== 0) { ret = TRUE; break; } } while( Process32Next(hHandle, &entry) ); } CloseToolhelp32Snapshot( hHandle ); return ret; } DWORD FIX_BX_R12(DWORD startAddress, DWORD callAddress) { writedword(startAddress, 0xE59FC000); writedword(startAddress + 4, 0xE12FFF1C); writedword(startAddress + 8, callAddress); // reserved, Not Used writedword(startAddress + 12, 0x00000000); return startAddress + 16; } void startAndPatchApplication(CString strAppFileName, BOOL &found) { STARTUPINFO si; PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(PROCESS_INFORMATION)); memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); DWORD fdwCreate = (found ? NULL : CREATE_SUSPENDED); if (CreateProcess(strAppFileName.GetBuffer(0), strAppFileName.GetBuffer(0), NULL, NULL, FALSE, fdwCreate, NULL, NULL, &si, &pi)) //if (CreateProcess(strAppFileName.GetBuffer(0), strAppFileName.GetBuffer(0), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { if (found) goto __EXIT__; SetKMode(TRUE); SetProcPermissions(0xFFFFFFFF); _pid = pi.hProcess; HMODULE hModule = LoadLibrary(L"ptv10.dll"); FARPROC ts = GetProcAddress(hModule, (LPCWSTR)MAKELONG(1, 0)); //ts = (FARPROC)MapPtrToProcess(ts, _pid); FARPROC sipMakeCall = GetProcAddress(hModule, (LPCWSTR)MAKELONG(2, 0)); //applyATrick = (FARPROC)MapPtrToProcess(applyATrick, _pid); FARPROC sipAnswerCall = GetProcAddress(hModule, (LPCWSTR)MAKELONG(3, 0)); FARPROC sipRejectCall = GetProcAddress(hModule, (LPCWSTR)MAKELONG(4, 0)); FARPROC sipTerminateCall = GetProcAddress(hModule, (LPCWSTR)MAKELONG(5, 0)); FARPROC resetATrick = GetProcAddress(hModule, (LPCWSTR)MAKELONG(6, 0)); FARPROC call_WideCharToMultiByte = GetProcAddress(hModule, (LPCWSTR)MAKELONG(7, 0)); FARPROC call_MultiByteToWideChar = GetProcAddress(hModule, (LPCWSTR)MAKELONG(8, 0)); FARPROC callWindowProcFake = GetProcAddress(hModule, (LPCWSTR)MAKELONG(9, 0)); FARPROC sipEnableHeadset = GetProcAddress(hModule, (LPCWSTR)MAKELONG(10, 0)); FARPROC onSpeakerClick = GetProcAddress(hModule, (LPCWSTR)MAKELONG(11, 0)); DWORD pMemAddress = 0x00102000; uint32_t ip = 0x00022F00; DWORD offset = (pMemAddress - ip - 8) >> 2;; offset = offset & 0x00FFFFFF; ip = 0xEB000000 ^ offset; writedword(0x00022F00, ip); writedword(0x00022F04, 0xEA00001A); writedword(0x00022F74, 0xE1A03000); pMemAddress = FIX_BX_R12(pMemAddress, (uint32_t)ts); ip = 0x00027C78; offset = (pMemAddress - ip - 8) >> 2; offset = offset & 0x00FFFFFF; ip = 0xEB000000 ^ offset; writedword(0x00027C78, ip); pMemAddress = FIX_BX_R12(pMemAddress, (uint32_t)sipMakeCall); ip = 0x0002817C; offset = (pMemAddress - ip - 8) >> 2; offset = offset & 0x00FFFFFF; ip = 0xEB000000 ^ offset; writedword(0x0002817C, ip); pMemAddress = FIX_BX_R12(pMemAddress, (uint32_t)sipAnswerCall); ip = 0x00028410; offset = (pMemAddress - ip - 8) >> 2; offset = offset & 0x00FFFFFF; ip = 0xEB000000 ^ offset; writedword(0x00028410, ip); pMemAddress = FIX_BX_R12(pMemAddress, (uint32_t)sipRejectCall); ip = 0x00028B38; offset = (pMemAddress - ip - 8) >> 2; offset = offset & 0x00FFFFFF; ip = 0xEB000000 ^ offset; writedword(0x00028B38, ip); pMemAddress = FIX_BX_R12(pMemAddress, (uint32_t)sipTerminateCall); //.text:00026D34 BL sub_29A90 没接听的时候,对方关闭 //.text:00026D44 BL sub_29C98 接听后,对方关闭 //fix: Cannot restore volume when remote user to end call // CR1, 先跳转到补丁代码,执行完补丁后跳回 DWORD jmp2Addr = pMemAddress; pMemAddress += 16; ip = 0x00026D38; offset = (jmp2Addr - ip - 8) >> 2; offset = offset & 0x00FFFFFF; ip = 0xEA000000 ^ offset; writedword(0x00026D38, ip); ip = jmp2Addr; offset = (pMemAddress - ip - 8) >> 2; offset = offset & 0x00FFFFFF; ip = 0xEB000000 ^ offset; writedword(jmp2Addr, ip); ip = jmp2Addr + 4; offset = (0x00026DC8 - ip - 8) >> 2; offset = offset & 0x00FFFFFF; ip = 0xEA000000 ^ offset; writedword(jmp2Addr + 4, ip); pMemAddress = FIX_BX_R12(pMemAddress, (uint32_t)resetATrick); // CR2 ip = 0x00026D48; offset = (jmp2Addr - ip - 8) >> 2; offset = offset & 0x00FFFFFF; ip = 0xEA000000 ^ offset; writedword(0x00026D48, ip); #if USE_AES_ENCODE_PASSWORD // NEW feature :encode password by base64(AES(UTF8(plainText))) // 1.1). replace calling address(00024074) ip = 0x00024074; offset = (pMemAddress - ip - 8) >> 2; offset = offset & 0x00FFFFFF; ip = 0xEB000000 ^ offset; writedword(0x00024074, ip); // 1.2). place call_WideCharToMultiByte@pv10.dll address pMemAddress = FIX_BX_R12(pMemAddress, (uint32_t)call_WideCharToMultiByte); // 2.1). replace calling address(0x00024AE0) ip = 0x00024AE0; offset = (pMemAddress - ip - 8) >> 2; offset = offset & 0x00FFFFFF; ip = 0xEB000000 ^ offset; writedword(0x00024AE0, ip); // 2.2). place call_MultiByteToWideChar@pv10.dll address pMemAddress = FIX_BX_R12(pMemAddress, (uint32_t)call_MultiByteToWideChar); #endif #if USE_HOOK_WINDOW_PROC ip = 0x000339E4; offset = (pMemAddress - ip - 8) >> 2; offset = offset & 0x00FFFFFF; ip = 0xEB000000 ^ offset; writedword(0x000339E4, ip); pMemAddress = FIX_BX_R12(pMemAddress, (uint32_t)callWindowProcFake); #endif // Fix issue that speaker cannot work properly on some phones // It should be caused by driver which is not compatible with OS API // 1.1) FIX_BX_R12(0x000834CC, (uint32_t)sipEnableHeadset); // 2.1) ip = 0x0001453C; offset = (pMemAddress - ip - 8) >> 2; offset = offset & 0x00FFFFFF; ip = 0xEB000000 ^ offset; writedword(0x0001453C, ip); // 2.2) pMemAddress = FIX_BX_R12(pMemAddress, (uint32_t)onSpeakerClick); ::ResumeThread(pi.hThread); #if 1 CALLBACKINFO cbi; cbi.hProc = _pid; hModule= LoadLibrary(_T("coredll.dll")); cbi.pfn = (FARPROC)GetProcAddress(hModule, _T("LoadLibraryW")); cbi.pvArg0 = (LPVOID)MapPtrToProcess((LPVOID)_T("ptv10.dll"), GetCurrentProcess()); Sleep(100); HINSTANCE hInst = (HINSTANCE)PerformCallBack4(&cbi, 0, 0, 0); Sleep(5000); #endif #if 0 MSG msg; DWORD reason = WAIT_TIMEOUT; while (WAIT_OBJECT_0 != reason) { reason = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE, QS_ALLINPUT); switch (reason) { case WAIT_OBJECT_0: // Your child process is finished. break; case (WAIT_OBJECT_0 + 1): // A message is available in the message queue. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); // Note that if your main message loop does additional processing // (such as calling IsDialogMessage() for modeless dialogs) // you will want to do those things here, too. } break; } } #endif __EXIT__: CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } }
小插曲:
当时第一次实现后发现在WinMobile 6.0可用,但是WinMobile 6.5不能用。
后来发现是因为当时修改的函数跳转问题,因为BL相当于短地址跳转,而我们注入的函数代码,地址很长,
后来用BX替换,统一通过FIX_BX_R12函数替换。
BL 跳转地址偏移量计算方法:
offset = (pMemAddress – ip – 8) >> 2;
2、注入模块部分代码:
#include "stdafx.h" #include "AudioDevice.h" #include "md5\md5class.h" #include "base64\base64.h" #include "aes\aes_wrap.h" #include "AesCBC128.h" #define ATRICK_BY_DRIVER 0 #define ATRICK_BY_REGISTRY 0 #define USE_AES_ENCODE_PASSWORD 0 #define USE_LIMIT_DATETIME 1 #define FEATURE_GPRS 0 static HMODULE sipcore_handle = NULL; static HBRUSH g_bgSolidBrush = NULL; static HBRUSH g_bgBottomSolidBrush = NULL; static BOOL* g_pIsUseSpeaker = NULL; typedef bool (__stdcall *t_makeCall)(HANDLE SIPCoreLib, LPCTSTR callTo, bool sendSDP); typedef bool (__stdcall *t_answerCall)(HANDLE SIPCoreLib, long sessionId); typedef void (__stdcall *t_rejectCall)(HANDLE SIPCoreLib, long sessionId, int code, LPCTSTR reason); typedef void (__stdcall *t_terminateCall)(HANDLE SIPCoreLib, long sessionId); typedef void (__stdcall *t_enableHeadset)(HANDLE SIPCoreLib, BOOL bEnable); void WINAPI sipEnableHeadset(HANDLE SIPCoreLib,BOOL bEnable); t_makeCall makeCall = NULL; t_answerCall answerCall = NULL; t_rejectCall rejectCall = NULL; t_terminateCall terminateCall = NULL; t_enableHeadset enableHeadset = NULL; BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { RETAILMSG(TRUE, (_T("Enter DllMain, ul_reason_for_call=%d\r\n"), ul_reason_for_call)); if(ul_reason_for_call == DLL_PROCESS_ATTACH) { #if FEATURE_GPRS if (kDllLoadedCounter == 0) { DWORD dwStatus = 0; HRESULT hr = EstablishConnection(NULL, 10, 25000, &dwStatus, hConnection); kDllLoadedCounter++; } #endif sipcore_handle = LoadLibrary(_T("sipcore.dll")); if (sipcore_handle == NULL) return TRUE; makeCall = (t_makeCall)GetProcAddress(sipcore_handle, (LPCWSTR)MAKELONG(8, 0)); answerCall = (t_answerCall)GetProcAddress(sipcore_handle, (LPCWSTR)MAKELONG(10, 0)); rejectCall = (t_rejectCall)GetProcAddress(sipcore_handle, (LPCWSTR)MAKELONG(9, 0)); terminateCall = (t_terminateCall)GetProcAddress(sipcore_handle, (LPCWSTR)MAKELONG(11, 0)); enableHeadset = (t_enableHeadset)GetProcAddress(sipcore_handle, (LPCWSTR)MAKELONG(48, 0)); g_bgSolidBrush = CreateSolidBrush(RGB(135, 195, 229)); g_bgBottomSolidBrush = CreateSolidBrush(RGB(10, 47, 152)); #if 0 HWND theMainWnd = GetActiveWindow(); RETAILMSG(TRUE, (_T("Enter DllMain, theMainWnd=0x%x\r\n"), theMainWnd)); if (theMainWnd != NULL) { g_pOldWndProc = (WNDPROC)GetWindowLong(theMainWnd, DWL_DLGPROC); RETAILMSG(TRUE, (_T("Enter DllMain, g_pOldWndProc=0x%x\r\n"), g_pOldWndProc)); if (g_pOldWndProc != NULL) { SetWindowLong(theMainWnd, DWL_DLGPROC, (LONG)NewWindowProc); } } #endif #if USE_LIMIT_DATETIME checkDateTime(); #endif } else if(ul_reason_for_call == DLL_PROCESS_DETACH) { if (sipcore_handle != NULL) { FreeLibrary(sipcore_handle); sipcore_handle = NULL; } if (g_bgSolidBrush != NULL) { DeleteObject(g_bgSolidBrush); g_bgSolidBrush = NULL; } if (g_bgBottomSolidBrush != NULL) { DeleteObject(g_bgBottomSolidBrush); g_bgBottomSolidBrush = NULL; } #if FEATURE_GPRS if (kDllLoadedCounter == 1) { ConnMgrReleaseConnection(hConnection, TRUE); } #endif } return TRUE; } // …… // 省略部分代码 BOOL WINAPI ForceSpeaker(BOOL bSpeaker) { DWORD dwTreadId = 0 ; UINT DevNum = 0; UINT i; WAVEOUTCAPS caps; DevNum = waveOutGetNumDevs(); /*获取音频设备个数*/ if (0 == DevNum) { return FALSE; } memset(&caps, 0, sizeof(caps)); /*获取音频设备的编号*/ for (i = 0; i < DevNum; i++) { if (MMSYSERR_NOERROR != waveOutGetDevCaps(i, &caps, sizeof(caps))) { return FALSE; } if (0 == wcscmp(_T("Audio Output"), caps.szPname)) { break; } /*找不到音频设备*/ if (DevNum - 1 == i) { return FALSE; } } HWAVEOUT hwo = (HWAVEOUT)i; UINT uMsg = MM_WOM_FORCESPEAKER; if (MMSYSERR_NOERROR != waveOutMessage(hwo, uMsg, bSpeaker, 4)) { return FALSE; } return TRUE; } void WINAPI sipEnableHeadset(HANDLE SIPCoreLib,BOOL bEnable) { if (!g_isValidDateTime) return; DEBUGMSG(TRUE, (L"Enter sipEnableHeadset(), enableHeadset=0x%x, bEnable=%d\r\n", enableHeadset, bEnable)); #if 0 // RIL API if (hRil != NULL) { RILAUDIODEVICEINFO audioDeviceInfo; audioDeviceInfo.cbSize = sizeof(audioDeviceInfo); audioDeviceInfo.dwParams = RIL_PARAM_ADI_ALL; if (bEnable) { audioDeviceInfo.dwRxDevice = RIL_AUDIO_HANDSET; audioDeviceInfo.dwTxDevice = RIL_AUDIO_HANDSET; } else { audioDeviceInfo.dwRxDevice = RIL_AUDIO_NONE; audioDeviceInfo.dwTxDevice = RIL_AUDIO_NONE; } DEBUGMSG(TRUE, (L"audioDeviceInfo.dwRxDevice = %d, audioDeviceInfo.dwTxDevice = %d\r\n"), audioDeviceInfo.dwRxDevice, audioDeviceInfo.dwRxDevice); DWORD hr = RIL_SetAudioDevices(hRil, &audioDeviceInfo); //RIL_SetAudioMuting(hRil, FALSE); } #endif ForceSpeaker(bEnable); ////if (bEnable) //{ // if (enableHeadset == NULL) return; // enableHeadset(SIPCoreLib, bEnable); //} ////else //{ // //CAudDev audioObj; // //audioObj.Open(); // //audioObj.enableHeadset(bEnable); // //audioObj.Close(); //} } typedef void (__stdcall *t_doCallEnableHeadset)(char *p1, char *p2); t_doCallEnableHeadset doCallEnableHeadset = NULL; void onSpeakerClick(char *p1, char *p2) { DEBUGMSG(TRUE, (L"Enter onSpeakerClick(), p1 = 0x%x\r\n", p1)); g_pIsUseSpeaker = (BOOL *)(p1 + 0x529C); DEBUGMSG(TRUE, (L"g_pIsUseSpeaker = 0x%x\r\n", g_pIsUseSpeaker)); // 0x00028794 disassemble address from main application doCallEnableHeadset = (t_doCallEnableHeadset)0x00028794; doCallEnableHeadset(p1, p2); }
小插曲2:
关于手机听筒扬声器切换问题,用了很多方法都不好用,WinMobile标准API不好用,
原因是手机厂商未对其实现。即便用了当时方案商提供的手册来直接控制IO,也不行,
第一次好用后,就失灵了。手机当时用的是华为海思K3的芯片,
最后经与华为海思相关工程师沟通,最终确定是海思设计的驱动问题。
当时IO控制代码如下:
#include "StdAfx.h" #include "AudioDevice.h" //add for Hi6421 #define CSPI_IOCTL_READ6421 0x11 #define CSPI_IOCTL_WRITE6421 0x12 #define CSPI_IOCTL_SETBIT6421 0x13 #define CSPI_IOCTL_CLRBIT6421 0x14 // Audio Codec Digital Registers Index #define Hi6421_ACODEC_LDO13 0x0E #define Hi6421_ACODEC_RESET 0x2C #define Hi6421_ACODEC_DACLR 0x2F #define Hi6421_ACODEC_DACV 0x30 #define Hi6421_ACODEC_ADCLR 0x31 #define Hi6421_ACODEC_LOOPBACK_ST 0x32 #define Hi6421_ACODEC_DACL_VOLA 0x33 #define Hi6421_ACODEC_DACL_VOLB 0x34 #define Hi6421_ACODEC_DACR_VOLA 0x35 #define Hi6421_ACODEC_DACR_VOLB 0x36 #define Hi6421_ACODEC_DACV_VOLA 0x37 #define Hi6421_ACODEC_DACV_VOLB 0x38 #define Hi6421_ACODEC_ADCL_VOLA 0x39 #define Hi6421_ACODEC_ADCL_VOLB 0x3A #define Hi6421_ACODEC_ADCR_VOLA 0x3B #define Hi6421_ACODEC_ADCR_VOLB 0x3C #define Hi6421_ACODEC_ST_VOLA 0x3D #define Hi6421_ACODEC_ST_VOLB 0x3E #define Hi6421_ACODEC_S1 0x3F #define Hi6421_ACODEC_S2 0x40 #define Hi6421_ACODEC_FS_SEL 0x41 #define Hi6421_ACODEC_DAC_DTH_CPST 0x42 #define Hi6421_ACODEC_RVD_0X43 0x43 // reserved registers #define Hi6421_ACODEC_RVD_0X44 0x44 // reserved registers #define Hi6421_ACODEC_RVD_0X45 0x45 // reserved registers #define Hi6421_ACODEC_RVD_0X46 0x46 // reserved registers // Audio Codec Analogue Registers Index #define Hi6421_ACODEC_LSP_CTRL 0x47 #define Hi6421_ACODEC_EAR_CTRL 0x48 #define Hi6421_ACODEC_LO_CTRL 0x49 #define Hi6421_ACODEC_HSL_CTRL 0x4A #define Hi6421_ACODEC_HSR_CTRL 0x4B #define Hi6421_ACODEC_PA_MIXER 0x4C #define Hi6421_ACODEC_LM 0x4D #define Hi6421_ACODEC_RM 0x4E #define Hi6421_ACODEC_ADCL_ANA 0x4F #define Hi6421_ACODEC_ADCR_ANA 0x50 #define Hi6421_ACODEC_MIC1 0x51 #define Hi6421_ACODEC_ST_ANA 0x52 #define Hi6421_ACODEC_LIN1 0x53 #define Hi6421_ACODEC_LIN2 0x54 #define Hi6421_ACODEC_LIN3 0x55 #define Hi6421_ACODEC_MIC2 0x56 #define Hi6421_ACODEC_PLL1 0x57 #define Hi6421_ACODEC_CM_CTRL 0x58 #define Hi6421_ACODEC_RVD_0X59 0x59 // reserved registers #define Hi6421_ACODEC_RVD_0X5A 0x5A // reserved registers #define Hi6421_ACODEC_RVD_0X5B 0x5B // reserved registers #define Hi6421_ACODEC_RVD_0X5C 0x5C // reserved registers #define Hi6421_ACODEC_RVD_0X5D 0x5D // reserved registers #define Hi6421_ACODEC_RVD_0X5E 0x5E // reserved registers #define Hi6421_ACODEC_RVD_0X5F 0x5F // reserved registers #define Hi6421_ACODEC_RVD_0X60 0x60 // reserved registers // 8-bit wide #define ACODEC_BITMASK8(bw,bs) ((UCHAR)((bw==8)?0xFF:(((1U << bw)-1))<<bs)) #define ACODEC_BITCLEAR8(data, bw, bs) ((UCHAR)data & (~(ACODEC_BITMASK8(bw, bs)))) #define ACODEC_BITSET8(data, bw, bs, val) \ ((ACODEC_BITCLEAR8(data, bw, bs)) \ |((UCHAR)((UCHAR)(val)<<(UCHAR)(bs))&(UCHAR)(ACODEC_BITMASK8(bw, bs)))) #define ACODEC_BITGET8(data, bw, bs) \ ((UCHAR)(((data) & ((UCHAR)ACODEC_BITMASK8(bw, bs))) >> (bs))) typedef struct { UINT8 index; //6421中待读写寄存器偏移量 UINT8 xchCnt; //读写6421寄存器个数 UINT8 reserved[2]; //用于字节对齐 LPVOID pBuf; //spi发送/接收buffer首地址 }CSPI_6421_PKT_T, *PCSPI_6421_PKT_T; //add end CAudDev::CAudDev() : m_hWav(NULL) { } CAudDev::~CAudDev() { } BOOL CAudDev::Open() { BOOL bResult = TRUE; if (NULL == m_hWav) { // Open WAV device //m_hWav = CreateFile(L"WAV1:", 0, 0, NULL, 0, 0, NULL); m_hWav = CreateFile(TEXT("SPI3:"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (m_hWav == INVALID_HANDLE_VALUE) { m_hWav = NULL; bResult = FALSE; RETAILMSG(1, (L"Failed open SPI3: device driver\r\n")); } else { //保存原来的数值 } } return bResult; } BOOL CAudDev::enableHeadset(BOOL bEnable) { BOOL bResult = FALSE; if (m_hWav != NULL) { UCHAR ucVal; CSPI_6421_PKT_T busXferPack; UCHAR N = 0; // 麦克风1 busXferPack.index = Hi6421_ACODEC_MIC1; busXferPack.xchCnt = sizeof(UCHAR); ucVal = 0x42;//(bEnable ? 0x09 : 0x0A); busXferPack.pBuf = &ucVal; bResult = DeviceIoControl(m_hWav, CSPI_IOCTL_WRITE6421, &busXferPack, sizeof(CSPI_6421_PKT_T), NULL, NULL, NULL, NULL); RETAILMSG(1, (L"Hi6421_ACODEC_MIC1, write register result=%d, ucVal=0x%x\r\n", bResult, ucVal)); // 扬声器寄存器 busXferPack.index = Hi6421_ACODEC_LSP_CTRL; busXferPack.xchCnt = sizeof(UCHAR); busXferPack.pBuf = &ucVal; bResult = DeviceIoControl(m_hWav, CSPI_IOCTL_READ6421, &busXferPack, sizeof(CSPI_6421_PKT_T), NULL, NULL, NULL, NULL); RETAILMSG(1, (L"Hi6421_ACODEC_LSP_CTRL, read register result=%d, ucVal=0x%x\r\n", bResult, ucVal)); // 听筒寄存器 busXferPack.index = Hi6421_ACODEC_EAR_CTRL; busXferPack.xchCnt = sizeof(UCHAR); busXferPack.pBuf = &ucVal; bResult = DeviceIoControl(m_hWav, CSPI_IOCTL_READ6421, &busXferPack, sizeof(CSPI_6421_PKT_T), NULL, NULL, NULL, NULL); RETAILMSG(1, (L"Hi6421_ACODEC_EAR_CTRL, read register result=%d, ucVal=0x%x\r\n", bResult, ucVal)); //Hi6421_ACODEC_LO_CTRL busXferPack.index = Hi6421_ACODEC_LO_CTRL; busXferPack.xchCnt = sizeof(UCHAR); busXferPack.pBuf = &ucVal; bResult = DeviceIoControl(m_hWav, CSPI_IOCTL_READ6421, &busXferPack, sizeof(CSPI_6421_PKT_T), NULL, NULL, NULL, NULL); RETAILMSG(1, (L"Hi6421_ACODEC_LO_CTRL, read register result=%d, ucVal=0x%x\r\n", bResult, ucVal)); //Hi6421_ACODEC_PA_MIXER busXferPack.index = Hi6421_ACODEC_PA_MIXER; busXferPack.xchCnt = sizeof(UCHAR); busXferPack.pBuf = &ucVal; bResult = DeviceIoControl(m_hWav, CSPI_IOCTL_READ6421, &busXferPack, sizeof(CSPI_6421_PKT_T), NULL, NULL, NULL, NULL); RETAILMSG(1, (L"Hi6421_ACODEC_PA_MIXER, read register result=%d, ucVal=0x%x\r\n", bResult, ucVal)); // busXferPack.index = Hi6421_ACODEC_MIC1; busXferPack.xchCnt = sizeof(UCHAR); busXferPack.pBuf = &ucVal; bResult = DeviceIoControl(m_hWav, CSPI_IOCTL_READ6421, &busXferPack, sizeof(CSPI_6421_PKT_T), NULL, NULL, NULL, NULL); RETAILMSG(1, (L"Hi6421_ACODEC_MIC1, read register result=%d, ucVal=0x%x\r\n", bResult, ucVal)); //Hi6421_ACODEC_CM_CTRL busXferPack.index = Hi6421_ACODEC_CM_CTRL; busXferPack.xchCnt = sizeof(UCHAR); busXferPack.pBuf = &ucVal; bResult = DeviceIoControl(m_hWav, CSPI_IOCTL_READ6421, &busXferPack, sizeof(CSPI_6421_PKT_T), NULL, NULL, NULL, NULL); RETAILMSG(1, (L"Hi6421_ACODEC_CM_CTRL, read register result=%d, ucVal=0x%x\r\n", bResult, ucVal)); } return bResult; } void CAudDev::Close() { if (m_hWav != NULL) { CloseHandle(m_hWav); m_hWav = NULL; } }