1 研究背景
1.1 研究现状
百度语音合成(Text to Speech)目前已能正常语音合成或停止合成功能,但因临时授权文件的初始日期会与设备系统的日期比较,若设备系统时间超过授权文件初始日期30天即为过期无法进行语音合成,存在缺陷。
1.2研究目的和意义
设备使用百度语音合成来进行语音提示时能正常播放。
2 项目主要研究内容
2.1 主要工作内容
①分析临时授权文件和百度语音so动态库,寻找突破口
②研究所有so动态库授权相关内容
③修改so动态库
④真机测试
2.2 具体实施方案
2.2.1 分析现有文件,寻找突破口
2.2.1.1 分析授权文件,尝试破解加密内容(RSA加密)没成功,转从修改so动态库入手。
2.2.1.2查找所有与授权相关内容的动态库
libbd_etts.so包含获取当前日期和获取授权文件、及二者日期比较
libbdtts.so 包含获取授权文件和验证授权文件有效函数
libgnustl_shared.so 包含处理时间等函数
2.2.1.3 分析相关函数,初步确认方案有:
①将获取到的授权文件日期更改
②授权文件日期与系统日期比较判断结果都改为可语音合成
③获取系统日期时返回值更改为自己设定日期
因方案①、②中的获取授权文件和日期比较函数中寄存器较多,同时不同so中皆有包含,修改复杂,最终采用方案③。
2.2.2 授权破解
2.2.2.1获取系统时间函数研究
通过IDA破解出来的汇编源码,研究程序结构及寄存器作用。
分析上图汇编源码,函数的程序流程大概为:
①time函数获取系统时间给寄存器R0
②使用gmtime函数将日期时间转为GMT时间,寄存器R5赋值为年份,R6为月份,R7为天数;
③memset给一字符串变量内存空间清零
④sprintf将字符串变量日期格式化,年份需加1900,月份日期各加1.
⑤返回字符串变量
将其复原为程序代码即为:
void *__fastcall etts::GetCurrTime(etts *this)
{
struct tm *SysDate; //r0寄存器
int year; // r5
int month; // r6
int day; // r7
time_t SysTime;
SysTime = time(0);
SysDate = gmtime(&SysTime);
year = SysDate->tm_year;
month = SysDate ->tm_mon;
day = SysDate ->tm_mday;
memset(&unk_128958,0, 0x80);
sprintf((char*)&unk_128958, "%d-%d-%d", year + 1900, month + 1, day + 1);
return &unk_128958;
}
2.2.2.2 修改so程序文件
刚开始打算将time函数获取系统时间改为一个常数,但汇编转为机器码时不符合导致出错,最后考虑把sprintf格式化日期字符串时的年份需加的1900做修改。
定位到代码段地址为000DD440处,目的为修改立即数0x760。
查看汇编代码二进制格式指令,高亮处即为地址000DD440的指令:
因指令集ADD.W比较特殊导致汇编转为机器码的工具无法正常转换
自己手动改所以无法凑整,修改后的汇编代码二进制格式指令为
在代码段源码中变为:
所以最终sprintf将字符串变量日期格式化时,年份加上的值为0x200 + 0xC = 512 + 12 = 524,程序源码修改后为:
void *__fastcall etts::GetCurrTime(etts *this)
{
struct tm *SysDate; //r0寄存器
int year; // r5
int month; // r6
int day; // r7
time_t SysTime;
SysTime = time(0);
SysDate = gmtime(&SysTime);
year = SysDate->tm_year;
month = SysDate->tm_mon;
day = SysDate->tm_mday;
memset(&unk_128958,0, 0x80);
sprintf((char*)&unk_128958, "%d-%d-%d", year + 524, month + 1, day + 1);
return &unk_128958;
}
综上,虽然仍然会获取系统的时间与授权文件时间进行比较,但有效年份多余出了 1900 – 524 = 1376 年。
2.2.2.3 真机测试
通过设置设备系统日期,发现其系统可设置日期范围为1970 ~ 2038年。
在设备上测试,设置任意系统时间,语音都能正常合成,同时当正在语音播放时调整音量,播放的音量能够立即改变。
3 结论
3.1 研究成果总结
设备在无法联网条件下,能够离线进行语音合成,不存在过期风险。
3.2 使用说明
①安装SpeakService.apk应用(即服务端)到设备。
②客户端程序加载SpeechService.jar包到工程,并调用其接口。
jar包中封装的语音合成接口函数:
public static void startSpeech(Context baseContext,Stringtext,int AudioType);
参数baseContext:客户端Activity的上下文;
参数text:需要语音合成的字符串
参数AudioType:语音合成类型(值为1-6)
1:STREAM_VOICE_CALL (A10设备的系统音量)
2:STREAM_ALARM (A10设备的按键音量)
3:STREAM_MUSIC (A10设备的多媒体音量)
4:STREAM_NOTIFICATION
5:STREAM_RING
6:STREAM_SYSTEM
jar包中封装的停止语音合成接口函数:
public static void stopSpeech();
③客户端Activity添加import com.speech.SpeechClass;
详情请下载:
http://download.csdn.net/download/p876643136/10270199