原理和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;
        }
    }

基于CSipSimple开发的VOIP网络电话 iCaller for Android

关于闪退问题: android6.0+后授权变为动态请求,录音,联系人都可以,但没加相机这个动态,所以需要手动去设置里开启下允许,然后就可以正常用了。 这个演示...

阅读全文

酷派 5217 电信版 ROM,ROOT方法,独家首发

ROM简介: 1、完美ROOT 2、去掉电信预置应用,比官方ROM大小减少了35.8% 3、修改了原来官方的桌面,去掉强制预装,更干净,养眼 4、默认关闭数据连接,避免首...

阅读全文

Windows Mobile SIP软电话,带G729编码

软件功能: 支持平台: Windows Mobile 6.1/6.5 支持服务端: Cisco CallManager, OpenSER, Kamailio, OpenSIPS, Asterisk, Radvision, Nortel, Avaya等等 支持...

阅读全文

欢迎留言