BLHeliSuite32逆向(三)

Crack,Reverse

Views:  times Updated on October 18, 2021 Posted by elmagnifico on July 20, 2021

Foreword

继续之前的,这里开始对配置内容进行解析,由于破解总是头尾一起开始的,所以之前已经先行看到了具体配置是怎么解读的了,只是没详细看内容而已。

配置解读

ReadSetupFromBinString

继续接着解密后看他是怎么赋值的

006EA46E        pop         ecx
006EA46F        mov         byte ptr [ebp-0E],al
006EA472        cmp         byte ptr [ebp-0E],4
# 跳转
006EA476>       jb          006EA482
...
# 继续
006EA482        mov         eax,dword ptr [ebp-8]
006EA485        lea         edx,[eax+30];TBLHeli.FEep_ESC_Layout:TESC_Layout
006EA488        mov         eax,dword ptr [ebp-4]
006EA48B        add         eax,40
006EA48E        mov         ecx,20
# 这里是在移动内存,eax是源地址,移动0x20个字节 32字节
# 这里就是给出了ESC_Layout的值
# 可以看到解密后配置的0x40开始,0x20个字节都是layout的字符串的值
# 我这里实际上是#HAKRC_35A#
006EA493        call        Move
006EA498        lea         edx,[ebp-14]
006EA49B        mov         eax,dword ptr [ebp-8]

继续看下一个值


006EA49E        call        006E6554
006EA4A3        mov         edx,dword ptr [ebp-14]
006EA4A6        mov         eax,dword ptr [ebp-8]
006EA4A9        add         eax,0B0;TBLHeli.FESC_Layout_Org_Str:string
006EA4AE        call        @UStrAsg
006EA4B3        cmp         byte ptr [ebp-0E],1
006EA4B7>       jbe         006EA4C3
006EA4B9        call        @TryFinallyExit
006EA4BE>       jmp         006EA95C
006EA4C3        mov         eax,dword ptr [ebp-4]
006EA4C6        movzx       eax,byte ptr [eax]
006EA4C9        mov         edx,dword ptr [ebp-8]
006EA4CC        mov         byte ptr [edx+4],al;TBLHeli.FEep_FW_Main_Revision:byte

可以看到这里直接取解密后第一个字节作为了 主版本号,也就是0x20,对应字符串的显示其实他是用32


006EA4CF        mov         eax,dword ptr [ebp-4]
006EA4D2        movzx       eax,byte ptr [eax+1]
006EA4D6        mov         edx,dword ptr [ebp-8]
006EA4D9        mov         byte ptr [edx+5],al;TBLHeli.FEep_FW_Sub_Revision:byte

同理下一个字符,子版本号,0x3C,对应成字符串显示就是60,实际显示的时他是主.子 然后还去掉了尾巴的0,实际显示出来就是32.6


006EA4DC        cmp         byte ptr [ebp-0E],1
006EA4E0>       je          006EA4EE
006EA4E2        mov         eax,dword ptr [ebp-8]
006EA4E5        call        006E7280
006EA4EA        test        al,al
# 1.跳转
006EA4EC>       je          006EA502
006EA4EE        mov         eax,dword ptr [ebp-8]
006EA4F1        mov         byte ptr [eax+0BA],1;TBLHeli.FIsAlternateSettingsKey:Boolean
006EA4F8        call        @TryFinallyExit
006EA4FD>       jmp         006EA95C
# 1.继续
006EA502        mov         ebx,dword ptr [ebp-4]
006EA505        movzx       eax,byte ptr [ebx+2]
006EA509        mov         edx,dword ptr [ebp-8]
006EA50C        mov         byte ptr [edx+6],al;TBLHeli.FEep_Layout_Revision:byte

这里拿第三字节作为layout的版本号,0x2A


006EA50F        mov         eax,dword ptr [ebp-8]
006EA512        movzx       eax,byte ptr [eax+4];TBLHeli.FEep_FW_Main_Revision:byte
006EA516        cmp         al,28
006EA518>       ja          006EA527
006EA51A        cmp         al,1F
006EA51C>       jb          006EA527
006EA51E        mov         eax,dword ptr [ebp-8]
006EA521        cmp         byte ptr [eax+5],63;TBLHeli.FEep_FW_Sub_Revision:byte
# 2.跳转
006EA525>       jbe         006EA535
006EA527        mov         byte ptr [ebp-0E],4
006EA52B        call        @TryFinallyExit
006EA530>       jmp         006EA95C
# 2.继续
006EA535        mov         eax,dword ptr [ebp-8]
006EA538        call        006E71CC
006EA53D        test        al,al
# 3.跳转
006EA53F>       jne         006EA54F
006EA541        mov         byte ptr [ebp-0E],4
006EA545        call        @TryFinallyExit
006EA54A>       jmp         006EA95C
# 3.继续
006EA54F        mov         eax,dword ptr [ebp-8]
006EA552        call        006E724C
006EA557        test        al,al
# 4.跳转
006EA559>       je          006EA569
006EA55B        mov         byte ptr [ebp-0E],2
006EA55F        call        @TryFinallyExit
006EA564>       jmp         006EA95C
# 4.继续
006EA569        mov         eax,dword ptr [ebp-8]
006EA56C        lea         edx,[eax+70];TBLHeli.FEep_Name:TESC_Name
006EA56F        lea         eax,[ebx+80]
006EA575        mov         ecx,10
006EA57A        call        Move

可以看到偏移0x80个字节后的16个字节是ESC Name,由于我这里是没命名的,所以全空,也就是space


006EA57F        movzx       eax,byte ptr [ebx+32]
006EA583        mov         edx,dword ptr [ebp-8]
006EA586        mov         byte ptr [edx+28],al;TBLHeli.FEep_Hw_LED_Capable_0:byte
006EA589        movzx       eax,byte ptr [ebx+33]
006EA58D        mov         edx,dword ptr [ebp-8]
006EA590        mov         byte ptr [edx+29],al;TBLHeli.FEep_Hw_LED_Capable_1:byte
006EA593        movzx       eax,byte ptr [ebx+34]
006EA597        mov         edx,dword ptr [ebp-8]
006EA59A        mov         byte ptr [edx+2A],al;TBLHeli.FEep_Hw_LED_Capable_2:byte
006EA59D        movzx       eax,byte ptr [ebx+35]
006EA5A1        mov         edx,dword ptr [ebp-8]
006EA5A4        mov         byte ptr [edx+2B],al;TBLHeli.FEep_Hw_LED_Capable_3:byte
006EA5A7        mov         eax,dword ptr [ebp-8]
006EA5AA        cmp         byte ptr [eax+28],0FF;TBLHeli.FEep_Hw_LED_Capable_0:byte
# 5.跳转
006EA5AE>       jne         006EA5B7

偏移0x32,0x33,0x34,0x35字节,他们都是LED使能字节,填入的LED的序号,我有3个,所以是123


006EA5B0        mov         eax,dword ptr [ebp-8]
006EA5B3        mov         byte ptr [eax+28],0;TBLHeli.FEep_Hw_LED_Capable_0:byte
# 继续 这里其实在判定是否这个led没有使能
006EA5B7        mov         eax,dword ptr [ebp-8]
006EA5BA        cmp         byte ptr [eax+29],0FF;TBLHeli.FEep_Hw_LED_Capable_1:byte
006EA5BE>       jne         006EA5C7
006EA5C0        mov         eax,dword ptr [ebp-8]
006EA5C3        mov         byte ptr [eax+29],0;TBLHeli.FEep_Hw_LED_Capable_1:byte
006EA5C7        mov         eax,dword ptr [ebp-8]
006EA5CA        cmp         byte ptr [eax+2A],0FF;TBLHeli.FEep_Hw_LED_Capable_2:byte
006EA5CE>       jne         006EA5D7
006EA5D0        mov         eax,dword ptr [ebp-8]
006EA5D3        mov         byte ptr [eax+2A],0;TBLHeli.FEep_Hw_LED_Capable_2:byte
006EA5D7        mov         eax,dword ptr [ebp-8]
006EA5DA        cmp         byte ptr [eax+2B],0FF;TBLHeli.FEep_Hw_LED_Capable_3:byte
006EA5DE>       jne         006EA5E7
006EA5E0        mov         eax,dword ptr [ebp-8]
006EA5E3        mov         byte ptr [eax+2B],0;TBLHeli.FEep_Hw_LED_Capable_3:byte

006EA5E7        movzx       eax,byte ptr [ebx+30]
006EA5EB        mov         edx,dword ptr [ebp-8]
006EA5EE        mov         byte ptr [edx+26],al;TBLHeli.FEep_Hw_Voltage_Sense_Capable:byte

偏移0x30个字节,这个是Voltage_Sense_Capable 是否使能的标记


006EA5F1        movzx       eax,byte ptr [ebx+31]
006EA5F5        mov         edx,dword ptr [ebp-8]
006EA5F8        mov         byte ptr [edx+27],al;TBLHeli.FEep_Hw_Current_Sense_Capable:byte

偏移0x31个字节,这个是Current_Sense_Capable 是否使能的标记

006EA5FB        mov         eax,dword ptr [ebp-8]
006EA5FE        cmp         byte ptr [eax+6],29;TBLHeli.FEep_Layout_Revision:byte
006EA602>       jb          006EA633
006EA604        movzx       eax,byte ptr [ebx+3F]
006EA608        mov         edx,dword ptr [ebp-8]
006EA60B        mov         byte ptr [edx+2F],al;TBLHeli.FEep_Nondamped_Capable:byte

偏移0x3F个字节,这个是Nondamped_Capable是否使能的标记,我这里是0x01 使能

006EA60E        movzx       eax,byte ptr [ebx+1C]
006EA612        mov         edx,dword ptr [ebp-8]
006EA615        mov         byte ptr [edx+20],al;TBLHeli.FEep_Note_Config:byte

偏移0x1C个字节,这个是Note_Config 就是音乐的配置,我这里速度是5间隔是0,所以是 0x50


006EA618        mov         eax,dword ptr [ebp-8]
006EA61B        lea         edx,[eax+80];TBLHeli.FEep_Note_Array:TEep_Note_Array
006EA621        lea         eax,[ebx+90]
006EA627        mov         ecx,30
006EA62C        call        Move

这里是音乐的编码,偏移0x90,然后之后0x30个字节都是乐谱,这个和我使用的音乐是完全可以对的上的,没有使用的字节就是0xFF

# 跳转
006EA631>       jmp         006EA641
006EA633        mov         eax,[00841290];^gvar_00839100
006EA638        movzx       eax,byte ptr [eax]
006EA63B        mov         edx,dword ptr [ebp-8]
006EA63E        mov         byte ptr [edx+2F],al;TBLHeli.FEep_Nondamped_Capable:byte
# 继续
006EA641        mov         eax,dword ptr [ebp-8]
006EA644        cmp         byte ptr [eax+6],2C;TBLHeli.FEep_Layout_Revision:byte
# 跳转
006EA648>       jb          006EA66C
...
# 继续
006EA66C        mov         eax,[00841290];^gvar_00839100
006EA671        movzx       eax,byte ptr [eax]
006EA674        mov         edx,dword ptr [ebp-8]
006EA677        mov         byte ptr [edx+2C],al;TBLHeli.FEep_Hw_Pwm_Freq_Min:byte
006EA67A        mov         eax,[00841290];^gvar_00839100
006EA67F        movzx       eax,byte ptr [eax]
006EA682        mov         edx,dword ptr [ebp-8]
006EA685        mov         byte ptr [edx+2D],al;TBLHeli.FEep_Hw_Pwm_Freq_Max:byte
006EA688        mov         eax,dword ptr [ebp-8]
006EA68B        cmp         byte ptr [eax+6],2D;TBLHeli.FEep_Layout_Revision:byte
# 跳转
006EA68F>       jb          006EA69D

这里不知道为什么,PWM Freq Min和Max 都是0xFF,这个值也不是从解密中读出来的,虽然解密中也有这个内容

但是我从解密后的buff中直接转换成短整型,就可以看到我pwm的设置,最低1040,中值1500,最高1960,但是没找到哪里调用了这部分数据

同理下面的FEep_SPORT_Capable,也都是0xFF,难道说是不限制?这里只是一个限制选项?


006EA691        movzx       eax,byte ptr [ebx+3E]
006EA695        mov         edx,dword ptr [ebp-8]
# 运动模式?
006EA698        mov         byte ptr [edx+2E],al;TBLHeli.FEep_SPORT_Capable:byte
006EA69B>       jmp         006EA6AB
# 继续
006EA69D        mov         eax,[00841290];^gvar_00839100
006EA6A2        movzx       eax,byte ptr [eax]
006EA6A5        mov         edx,dword ptr [ebp-8]
006EA6A8        mov         byte ptr [edx+2E],al;TBLHeli.FEep_SPORT_Capable:byte
006EA6AB        mov         bl,4
# 1. 循环 这里edi本质上来自于ebx
006EA6AD        mov         eax,ebx
# 这里这个函数会改变eax的值,所以edi来自于下面这个函数
# 这里edi由于是每次决定参数跳转几个字节,说白了就是从变量里读了一下占用了几个字节而已,然后对应赋值过去
# 相当于是偏移的一样的存在
006EA6AF        call        006DEB4C
006EA6B4        movzx       edi,al
006EA6B7        cmp         edi,0FF
006EA6BD>       je          006EA754
006EA6C3        mov         si,0FFFF
006EA6C7        mov         edx,ebx
006EA6C9        mov         eax,dword ptr [ebp-8]
006EA6CC        call        TBLHeli.IsParameterValid
006EA6D1        test        al,al
# 2.跳转 应该是参数有效
006EA6D3>       jne         006EA6E6
# 这里也有可能会不跳,继续走,继续走应该是参数无效了
# Pgm_Curr_Port 这个比较特殊,他的值是0xff,但是直接判定无效了
# 这就导致他后续走了设置默认值的分支
006EA6D5        cmp         bl,0F
006EA6D8>       jne         006EA748
006EA6DA        mov         eax,dword ptr [ebp-8]
006EA6DD        call        TBLHeli.IsCurrentProtectionFalselyHardEnabled
006EA6E2        test        al,al
006EA6E4>       je          006EA748
# 2.继续 这里的[ebp-4]刚好就是解密之后的buff首地址,所以关键就直接转变成了edi的来源
006EA6E6        mov         eax,dword ptr [ebp-4]
# 这里esi 是来自于eax+edi的
006EA6E9        movzx       esi,byte ptr [eax+edi]
006EA6ED        cmp         bl,0E
# 3.跳转
006EA6F0>       jne         006EA703
006EA6F2        cmp         si,0FF
006EA6F7>       jae         006EA703
006EA6F9        cmp         si,18
006EA6FD>       jb          006EA703
006EA6FF        sub         si,18
# 3.继续
006EA703        mov         eax,ebx
006EA705        call        006DEB58
006EA70A        cmp         al,1
# 4.跳转
006EA70C>       jbe         006EA71C
006EA70E        mov         eax,dword ptr [ebp-4]
006EA711        movzx       eax,byte ptr [eax+edi+1]
006EA716        shl         eax,8
006EA719        add         si,ax
# 4.继续
006EA71C        cmp         bl,11
# 5.跳转
006EA71F>       jne         006EA748
006EA721        mov         eax,dword ptr [ebp-8]
006EA724        call        TBLHeli.IsProgrammableBrakeForceCapable
006EA729        test        al,al
006EA72B>       jne         006EA748
006EA72D        mov         dl,11
006EA72F        mov         eax,dword ptr [ebp-8]
006EA732        call        TBLHeli.GetParameterMin
006EA737        cmp         si,ax
006EA73A>       jbe         006EA748
006EA73C        mov         dl,11
006EA73E        mov         eax,dword ptr [ebp-8]
006EA741        call        TBLHeli.GetParameterMax
006EA746        mov         esi,eax
# 5.继续
006EA748        mov         edx,ebx
# ecx来自于esi 反向找esi
006EA74A        mov         ecx,esi
006EA74C        mov         eax,dword ptr [ebp-8]
# 由于找了一遍全流程以后,发现剩余设置完全看不到,于是挨个函数里看到底是什么
# 这里就发现 SetParameterValueOrDefault 内有剩余所有参数的判定,怀疑是在这里进行的赋值,虽然名字不对
# 逆回来追踪ecx的值来自于哪里 
006EA74F        call        TBLHeli.SetParameterValueOrDefault
006EA754        inc         ebx
# 这里大概是要循环 0x1F-0x04个
006EA755        cmp         bl,1F 
# 1.这里是个大循环结尾
006EA758>       jne         006EA6AD
...

到这里基本所有参数含义就都可以确定了

核心配置参数

这里继续一下循环中依次处理的参数和其对应字节

偏移 字节 参数名称 参数值(大端) 实际参数对应名称
0x3 1 Pgm_Direction 0x01 Motor Direction
0x4 1 Pgm_Rampup_Pwr 0x32 Rampup Power
0x5 1 Pgm_Pwm_Frequency 0x18 PWM Frequency
0x6 1 Pgm_Comm_Timing 0x10 Motor Timing
0x7 1 Pgm_Demag_Comp 0x02 Demag Compensation
0x8 2 Pgm_Min_Throttle 0x410 Minimum Throttle
0xA 2 Pgm_Center_Throttle 0x5DC Throttle Cal Enable
0xC 2 Pgm_Max_Throttle 0x7A8 Maximum Throttle
0xE 1 Pgm_Enable_Throttle_Cal 0x0 Throttle Cal Enable
0xF 1 Pgm_Temp_Prot 0x0 Temperature Protection
0x10 1 Pgm_Volt_Prot 0x0 Low Voltage Protection
0x11 1 Pgm_Curr_Prot 0x0 这个参数也是无效的 ?
0x12 1 Pgm_Enable_Power_Prot 0x1 Low RPM Power Protect
0x13 1 Pgm_Brake_On_Stop 0x0 Brake On Stop
0x14 1 Pgm_Beep_Strength 0x28 Startup Beep Volume
0x15 1 Pgm_Beacon_Strength 0x50 Beacon/Signal Volume
0x16 2 Pgm_Beacon_Delay 0x0000 Beacon Delay
0x18 1 Pgm_LED_Control 0x0 LED Control
0x19 1 Pgm_Max_Acceleration 0x0 Maximum Acceleration
0x1A 1 Pgm_Nondamped_Mode 0x0 Non Damped Mode
0x1B 1 Pgm_Curr_Sense_Cal 0x64 这个参数也是无效的  
0x1C 1 Note_Config 0x50 Music Note Config
0x1D 1 Pgm_Sine_Mode 0x0 Sine Modulation Mode
0x1E 1 Pgm_Auto_Tlm_Mode 0x0 Auto Telemetry
0x1F 1 Pgm_Stall_Prot 0xFF 这个参数也是无效的  
0x20 1 Pgm_SBUS_Channel 0xFF 这个参数也是无效的  
0x21 1 Pgm_SPORT_Physical 0xFF 这个参数也是无效的  

再结合一下之前的Layout和Rev以及Music Data,基本上日常需要配置的信息就全了

SetParameterValueOrDefault

_Unit102.TBLHeli.SetParameterValueOrDefault
006E5914        push        ebx
006E5915        push        esi
006E5916        push        edi
# ecx来自于edi,而edi又来自于ecx,还要逆回去 看 ReadSetupFromBinString
006E5917        mov         edi,ecx
006E5919        mov         ebx,edx
006E591B        mov         esi,eax
006E591D        mov         edx,ebx
006E591F        mov         eax,esi
006E5921        call        TBLHeli.IsParameterValid
006E5926        test        al,al
006E5928>       je          006E5946
006E592A        mov         edx,ebx
006E592C        mov         ecx,edi
006E592E        mov         eax,esi
006E5930        call        TBLHeli.IsParameterValueInRange
006E5935        test        al,al
006E5937>       je          006E5946
006E5939        mov         edx,ebx
006E593B        mov         ecx,edi
006E593D        mov         eax,esi
# 果然名字和实际内容不一样,说是设置默认值,实际上是只有超过值范围的时候才会设置默认值,否则就是正常值
006E593F        call        TBLHeli.SetParameterValue
006E5944>       jmp         006E594F
006E5946        mov         edx,ebx
006E5948        mov         eax,esi
# 这里是设置默认值的
# Pgm_Curr_Port 这个比较特殊,他的值是0xff,但是上面直接判定无效了
# 这就导致他后续走了设置默认值的分支
006E594A        call        TBLHeli.SetParameterValueToDefault
006E594F        pop         edi
006E5950        pop         esi
006E5951        pop         ebx
006E5952        ret

SetParameterValue

这个函数基本就能看到剩余所有参数值,全都在这里了,是谁就设置谁。现在只要分析一下他数据具体是从哪个字节拿的就行了

_Unit102.TBLHeli.SetParameterValue
006E56B8        push        ebx
006E56B9        push        esi
006E56BA        push        edi
006E56BB        push        ecx
# esi刚开始来自于ecx,所以还要往外再追一层,倒回去看 SetParameterValueOrDefault
006E56BC        mov         esi,ecx
006E56BE        mov         ebx,edx
006E56C0        mov         edi,eax
006E56C2        mov         byte ptr [esp],1
006E56C6        mov         eax,ebx
006E56C8        call        006DEB58
006E56CD        cmp         al,2
006E56CF>       jae         006E56D8
# 又回来了,esi来自于esi
006E56D1        mov         eax,esi
006E56D3        movzx       eax,al
# esi来自于eax
006E56D6        mov         esi,eax
006E56D8        movzx       eax,bl
006E56DB        cmp         eax,29
006E56DE>       ja          006E5904
006E56E4        jmp         dword ptr [eax*4+6E56EB]
006E56EB        dd          006E5904
006E56EF        dd          006E5793
006E56F3        dd          006E579D
006E56F7        dd          006E57A7
006E56FB        dd          006E57B1
006E56FF        dd          006E57BB
006E5703        dd          006E57C5
006E5707        dd          006E57CF
006E570B        dd          006E57D9
006E570F        dd          006E57E3
006E5713        dd          006E57EC
006E5717        dd          006E57F5
006E571B        dd          006E57FE
006E571F        dd          006E5808
006E5723        dd          006E5812
006E5727        dd          006E581C
006E572B        dd          006E5826
006E572F        dd          006E5830
006E5733        dd          006E5855
006E5737        dd          006E585F
006E573B        dd          006E5869
006E573F        dd          006E5872
006E5743        dd          006E587C
006E5747        dd          006E5886
006E574B        dd          006E588D
006E574F        dd          006E5894
006E5753        dd          006E589B
006E5757        dd          006E58A2
006E575B        dd          006E58A9
006E575F        dd          006E58B0
006E5763        dd          006E58B7
006E5767        dd          006E5904
006E576B        dd          006E58BE
006E576F        dd          006E58C5
006E5773        dd          006E58CC
006E5777        dd          006E58D3
006E577B        dd          006E58DA
006E577F        dd          006E58E1
006E5783        dd          006E58E8
006E5787        dd          006E58EF
006E578B        dd          006E58F6
006E578F        dd          006E58FD
006E5793        mov         eax,esi
# 这里基本就是大型switch 但是问题是这里数据是来自于哪里
# 可以看到数值都是al的 al又是来自于esi
006E5795        mov         byte ptr [edi+4],al;TBLHeli.FEep_FW_Main_Revision:byte
006E5798>       jmp         006E5908
006E579D        mov         eax,esi
006E579F        mov         byte ptr [edi+5],al;TBLHeli.FEep_FW_Sub_Revision:byte
006E57A2>       jmp         006E5908
006E57A7        mov         eax,esi
006E57A9        mov         byte ptr [edi+6],al;TBLHeli.FEep_Layout_Revision:byte
006E57AC>       jmp         006E5908
006E57B1        mov         eax,esi
006E57B3        mov         byte ptr [edi+7],al;TBLHeli.FEep_Pgm_Direction:byte
006E57B6>       jmp         006E5908
006E57BB        mov         eax,esi
006E57BD        mov         byte ptr [edi+8],al;TBLHeli.FEep_Pgm_Rampup_Pwr:byte
006E57C0>       jmp         006E5908
006E57C5        mov         eax,esi
006E57C7        mov         byte ptr [edi+9],al;TBLHeli.FEep_Pgm_Pwm_Frequency:byte
006E57CA>       jmp         006E5908
006E57CF        mov         eax,esi
006E57D1        mov         byte ptr [edi+0A],al;TBLHeli.FEep_Pgm_Comm_Timing:byte
006E57D4>       jmp         006E5908
006E57D9        mov         eax,esi
006E57DB        mov         byte ptr [edi+0B],al;TBLHeli.FEep_Pgm_Demag_Comp:byte
006E57DE>       jmp         006E5908
# 由于有部分参数是需要2字节来完成的,所以这里是si赋值,本来al就来自于si,所以区别不大
006E57E3        mov         word ptr [edi+0C],si;TBLHeli.FEep_Pgm_Min_Throttle:word
006E57E7>       jmp         006E5908
006E57EC        mov         word ptr [edi+0E],si;TBLHeli.FEep_Pgm_Center_Throttle:word
006E57F0>       jmp         006E5908
006E57F5        mov         word ptr [edi+10],si;TBLHeli.FEep_Pgm_Max_Throttle:word
006E57F9>       jmp         006E5908
006E57FE        mov         eax,esi
006E5800        mov         byte ptr [edi+12],al;TBLHeli.FEep_Pgm_Enable_Throttle_Cal:Boolean
006E5803>       jmp         006E5908
006E5808        mov         eax,esi
006E580A        mov         byte ptr [edi+13],al;TBLHeli.FEep_Pgm_Temp_Prot:byte
006E580D>       jmp         006E5908
006E5812        mov         eax,esi
006E5814        mov         byte ptr [edi+14],al;TBLHeli.FEep_Pgm_Volt_Prot:byte
006E5817>       jmp         006E5908
006E581C        mov         eax,esi
006E581E        mov         byte ptr [edi+15],al;TBLHeli.FEep_Pgm_Curr_Prot:byte
006E5821>       jmp         006E5908
006E5826        mov         eax,esi
006E5828        mov         byte ptr [edi+16],al;TBLHeli.FEep_Pgm_Enable_Power_Prot:byte
006E582B>       jmp         006E5908
006E5830        mov         eax,edi
006E5832        call        TBLHeli.IsProgrammableBrakeForceCapable
006E5837        test        al,al
006E5839>       jne         006E584B
006E583B        test        si,si
006E583E>       jbe         006E584B
006E5840        mov         dl,11
006E5842        mov         eax,edi
006E5844        call        TBLHeli.GetParameterMax
006E5849        mov         esi,eax
006E584B        mov         eax,esi
006E584D        mov         byte ptr [edi+17],al;TBLHeli.FEep_Pgm_Brake_On_Stop:byte
006E5850>       jmp         006E5908
006E5855        mov         eax,esi
006E5857        mov         byte ptr [edi+18],al;TBLHeli.FEep_Pgm_Beep_Strength:byte
006E585A>       jmp         006E5908
006E585F        mov         eax,esi
006E5861        mov         byte ptr [edi+19],al;TBLHeli.FEep_Pgm_Beacon_Strength:byte
006E5864>       jmp         006E5908
006E5869        mov         word ptr [edi+1A],si;TBLHeli.FEep_Pgm_Beacon_Delay:word
006E586D>       jmp         006E5908
006E5872        mov         eax,esi
006E5874        mov         byte ptr [edi+1C],al;TBLHeli.FEep_Pgm_LED_Control:byte
006E5877>       jmp         006E5908
006E587C        mov         eax,esi
006E587E        mov         byte ptr [edi+1D],al;TBLHeli.FEep_Pgm_Max_Acceleration:byte
006E5881>       jmp         006E5908
006E5886        mov         eax,esi
006E5888        mov         byte ptr [edi+1E],al;TBLHeli.FEep_Pgm_Nondamped_Mode:byte
006E588B>       jmp         006E5908
006E588D        mov         eax,esi
006E588F        mov         byte ptr [edi+1F],al;TBLHeli.FEep_Pgm_Curr_Sense_Cal:byte
006E5892>       jmp         006E5908
006E5894        mov         eax,esi
006E5896        mov         byte ptr [edi+20],al;TBLHeli.FEep_Note_Config:byte
006E5899>       jmp         006E5908
006E589B        mov         eax,esi
006E589D        mov         byte ptr [edi+21],al;TBLHeli.FEep_Pgm_Sine_Mode:byte
006E58A0>       jmp         006E5908
006E58A2        mov         eax,esi
006E58A4        mov         byte ptr [edi+22],al;TBLHeli.FEep_Pgm_Auto_Tlm_Mode:byte
006E58A7>       jmp         006E5908
006E58A9        mov         eax,esi
006E58AB        mov         byte ptr [edi+23],al;TBLHeli.FEep_Pgm_Stall_Prot:byte
006E58AE>       jmp         006E5908
006E58B0        mov         eax,esi
006E58B2        mov         byte ptr [edi+24],al;TBLHeli.FEep_Pgm_SBUS_Channel:byte
006E58B5>       jmp         006E5908
006E58B7        mov         eax,esi
006E58B9        mov         byte ptr [edi+25],al;TBLHeli.FEep_Pgm_SPORT_Physical_ID:byte
006E58BC>       jmp         006E5908
006E58BE        mov         eax,esi
006E58C0        mov         byte ptr [edi+26],al;TBLHeli.FEep_Hw_Voltage_Sense_Capable:byte
006E58C3>       jmp         006E5908
006E58C5        mov         eax,esi
006E58C7        mov         byte ptr [edi+27],al;TBLHeli.FEep_Hw_Current_Sense_Capable:byte
006E58CA>       jmp         006E5908
006E58CC        mov         eax,esi
006E58CE        mov         byte ptr [edi+28],al;TBLHeli.FEep_Hw_LED_Capable_0:byte
006E58D1>       jmp         006E5908
006E58D3        mov         eax,esi
006E58D5        mov         byte ptr [edi+29],al;TBLHeli.FEep_Hw_LED_Capable_1:byte
006E58D8>       jmp         006E5908
006E58DA        mov         eax,esi
006E58DC        mov         byte ptr [edi+2A],al;TBLHeli.FEep_Hw_LED_Capable_2:byte
006E58DF>       jmp         006E5908
006E58E1        mov         eax,esi
006E58E3        mov         byte ptr [edi+2B],al;TBLHeli.FEep_Hw_LED_Capable_3:byte
006E58E6>       jmp         006E5908
006E58E8        mov         eax,esi
006E58EA        mov         byte ptr [edi+2C],al;TBLHeli.FEep_Hw_Pwm_Freq_Min:byte
006E58ED>       jmp         006E5908
006E58EF        mov         eax,esi
006E58F1        mov         byte ptr [edi+2D],al;TBLHeli.FEep_Hw_Pwm_Freq_Max:byte
006E58F4>       jmp         006E5908
006E58F6        mov         eax,esi
006E58F8        mov         byte ptr [edi+2E],al;TBLHeli.FEep_SPORT_Capable:byte
006E58FB>       jmp         006E5908
006E58FD        mov         eax,esi
006E58FF        mov         byte ptr [edi+2F],al;TBLHeli.FEep_Nondamped_Capable:byte
006E5902>       jmp         006E5908
006E5904        mov         byte ptr [esp],0
006E5908        movzx       eax,byte ptr [esp]
006E590C        pop         edx
006E590D        pop         edi
006E590E        pop         esi
006E590F        pop         ebx
006E5910        ret

后续UI更新

下面的内容其实是之前探索时记录的,这里也贴出来了。当时是顺序看一些,逆序看一些,然后互相印证,当然后来找到突破口以后,后续的这部分其实就不那么关键了。

SetupToControls

这里就比较关键了,找到了数据来源,这里理论上就是数据解析了

_Unit139.TBLHeliInterfaceManager.SetupToControls
007D2C78        push        ebx
007D2C79        cmp         word ptr [eax+35A],0;TBLHeliInterfaceManager.?f35A:word
007D2C81>       je          007D2C91
007D2C83        mov         ebx,eax
007D2C85        mov         eax,dword ptr [ebx+35C];TBLHeliInterfaceManager.?f35C:dword
007D2C8B        call        dword ptr [ebx+358];TBLHeliInterfaceManager.FOnSetupToControls
007D2C91        pop         ebx
007D2C92        ret

看到这么几句代码,当场自闭,显然这么几句不足以解释清楚这个数据是怎么显示到UI的。

猜测这里有点类似于C#的委托,这里只是允许UI进行更新,实际上UI在另一个线程里已经拿到了数据,并且进行了解析。

007D2C8B        call        dword ptr [ebx+358];TBLHeliInterfaceManager.FOnSetupToControls

关键是这一句,运行以后,UI才会真的更新,但是这里这是啥意思,我不知道,追的话,基本就看到了各个UI的控件的库函数好像被调用了。

到这里就不行了,必须要看一看SetupToControls和Send_cmd_DeviceReadBLHeliSetupSection之间的内容,看看拿到的这个256字节的数据他是怎么用的。看到这里再跳回到ReadSetupAll去看整个流程。

256字节处理

通过分析ReadSetupAll可以看到,从读取到数据到更新UI,只有2个函数,中间流程也很短,这里一步一步分析看看到底做了什么

007D5B31        movzx       edx,byte ptr [ebp-5]
007D5B35        mov         eax,dword ptr [ebp-4]
# 读取设置信息,这里就读到了256字节了
007D5B38        call        TBLHeliInterfaceManager.ReadDeviceSetupSection

# 将al中的值给到[ebp-7]的地址中
# OD中显示的实际上是:
# 007D5B3D        mov         byte ptr ss:[ebp-7],al
# 也就是将al的值,存入下面的地址中:从堆栈段寻址ebp-7,然后将这个地址对应的值转换成32位的数据
# 此时 eax的值是1,所以这里al自然就是1
# 此时 ebp的值是0x19F288
007D5B3D        mov         byte ptr [ebp-7],al
# 这里是读取[ebp-4]的给到eax中,应该是在传递参数
# ebp-4对应的地址是0x2864D00
007D5B40        mov         eax,dword ptr [ebp-4]
# 存储信息,这里意义不明,可能需要追看
007D5B43        call        TBLHeliInterfaceManager.BLHeliStored
# 此时eax=0x289D380 ebp=19F288  19F284中存储的是2864D00
007D5B48        mov         edx,dword ptr [ebp-4]
# edx=2864D00 处理后变成2864D44 再次变成0289D000
# 这里理论上应该就是把TBLHeli对象给进去了
007D5B4B        mov         edx,dword ptr [edx+44];TBLHeliInterfaceManager.FBLHeliWork:TBLHeli
# 这里已经写了7D5CE0这里是3,ecx=3
007D5B4E        movzx       ecx,byte ptr ds:[7D5CE0];0x3 gvar_007D5CE0
# 这里这个CopyTo是什么东西,也有可能是处理数据的地方
007D5B55        call        TBLHeli.CopyTo
007D5B5A        mov         eax,dword ptr [ebp-4]
# 将信息显示到控件
# 经过OD调试,发现拿到数据以后,在运行了TBLHeliInterfaceManager.SetupToControls之后UI就更新了,所以数据解析就在这个里面
007D5B5D        call        TBLHeliInterfaceManager.SetupToControls
007D5B62        mov         eax,dword ptr [ebp-4]

通过od,可以看到ebp此时的值其实是显示了一个字符串提示,这里应该不是关键

0x2864D00地址的内容:

BLHeliStored

Stored这里就很简单做了一个字节处理

_Unit139.TBLHeliInterfaceManager.BLHeliStored
# 此时eax是0x2564D00,+54以后是0x2564D54 对应的值是0x01
# edx是24003a000b5741539363920的一串数字,不知道是什么
007CC5DC        movzx       edx,byte ptr [eax+54];TBLHeliInterfaceManager.FCurrentESCNum:byte
# 执行完以后edx直接变成1了,所以这里对应注释就是当前esc数量 1
# eax=2864D00 edx=1
# 这里应该是返回值,[eax+edx*4+174]的值是2864E78
# 这里仔细一看其实不就是对象内存大小和ESC的数量有关系,每多一个那么对应大小就要多4个字节
007CC5E0        mov         eax,dword ptr [eax+edx*4+174]
# 执行完以后eax是0x289D380
007CC5E7        ret

这里数据是大端模式,80是低字节保存在内存的高地址上,而02是数据高字节,保存在内存低地址中

CopyTo

进入的时候,此时寄存器的值为:

额外发现这个CopyTo是经常被调用的,当

这两个Tab页面切换的时候,就会自动调用CopyTo.

我仔细对比了这两个Tab的内容,发现其实他们是一模一样的,只是在Setup页面可以设置,而Overview只能查看而已

_Unit102.TBLHeli.CopyTo
006E5490        push        ebp
006E5491        mov         ebp,esp
006E5493        add         esp,0FFFFFFF8
006E5496        push        ebx
006E5497        push        esi
006E5498        xor         ebx,ebx
006E549A        mov         dword ptr [ebp-4],ebx
006E549D        mov         byte ptr [ebp-5],cl
006E54A0        mov         esi,edx
006E54A2        mov         ebx,eax
006E54A4        xor         eax,eax
006E54A6        push        ebp
006E54A7        push        6E555C
006E54AC        push        dword ptr fs:[eax]
006E54AF        mov         dword ptr fs:[eax],esp
006E54B2        test        esi,esi
006E54B4>       je          006E5540
006E54BA        call        006DB734
006E54BF        test        al,al
006E54C1>       je          006E54C8
006E54C3        call        006DB87C
006E54C8        cmp         byte ptr [ebx+0C0],1;TBLHeli.FStatus:TSetupStatus
006E54CF>       ja          006E5534
006E54D1        lea         edx,[ebp-4]
006E54D4        mov         eax,ebx
# 这里比较可疑,通过上面的分析,大概知道了这里变成String,其实就是给overview去显示的
006E54D6        call        TBLHeli.WriteSetupToString
006E54DB        test        byte ptr [ebp-5],2
006E54DF>       je          006E54EE
006E54E1        movzx       eax,byte ptr [ebx+0D3];TBLHeli.FBootloaderRev:byte
006E54E8        mov         byte ptr [esi+0D3],al;TBLHeli.FBootloaderRev:byte
006E54EE        xor         ecx,ecx
006E54F0        mov         edx,dword ptr [ebp-4]
006E54F3        mov         eax,esi
# 这里虽然是解密,其实我感觉应该是恢复了一次解密内容
006E54F5        call        TBLHeli.ReadSetupFromBinString
006E54FA        test        byte ptr [ebp-5],1
006E54FE>       je          006E553B
006E5500        movzx       eax,byte ptr [ebx+0B9];TBLHeli.FActivationStatus:TActivationStatus
006E5507        mov         byte ptr [esi+0B9],al;TBLHeli.FActivationStatus:TActivationStatus
006E550D        mov         eax,dword ptr [ebx+0C4];TBLHeli.FDshotGoodFrames:Cardinal
006E5513        mov         dword ptr [esi+0C4],eax;TBLHeli.FDshotGoodFrames:Cardinal
006E5519        mov         eax,dword ptr [ebx+0C8];TBLHeli.FDshotBadFrames:Cardinal
006E551F        mov         dword ptr [esi+0C8],eax;TBLHeli.FDshotBadFrames:Cardinal
006E5525        movzx       eax,byte ptr [ebx+0D0];TBLHeli.FInputProtocol:byte
006E552C        mov         byte ptr [esi+0D0],al;TBLHeli.FInputProtocol:byte
# 1.这里会跳转
006E5532>       jmp         006E553B
006E5534        mov         eax,esi
006E5536        call        TBLHeli.Init
# 1.跳转到这里
006E553B        call        006DB89C
006E5540        xor         eax,eax
006E5542        pop         edx
006E5543        pop         ecx
006E5544        pop         ecx
006E5545        mov         dword ptr fs:[eax],edx
006E5548        push        6E5563
006E554D        lea         eax,[ebp-4]
006E5550        mov         edx,dword ptr ds:[404B48];TArray<System.Byte>
006E5556        call        @DynArrayClear
# 到这里就退出了
006E555B        ret
006E555C>       jmp         @HandleFinally
006E5561>       jmp         006E554D
006E5563        pop         esi
006E5564        pop         ebx
006E5565        pop         ecx
006E5566        pop         ecx
006E5567        pop         ebp
006E5568        ret

WriteSetupToString

此时寄存器为:

_Unit102.TBLHeli.WriteSetupToString
006EA9C8        push        ebx
006EA9C9        push        esi
006EA9CA        push        edi
006EA9CB        push        ebp
006EA9CC        add         esp,0FFFFFFF8
006EA9CF        mov         dword ptr [esp],edx
006EA9D2        mov         esi,eax
006EA9D4        push        0C0
006EA9D9        mov         eax,dword ptr [esp+4]
006EA9DD        mov         ecx,1
006EA9E2        mov         edx,dword ptr ds:[404B48];TArray<System.Byte>
006EA9E8        call        @DynArraySetLength
006EA9ED        add         esp,4
006EA9F0        mov         ecx,dword ptr ds:[841290];^gvar_00839100
006EA9F6        movzx       ecx,byte ptr [ecx]
006EA9F9        mov         eax,dword ptr [esp]
006EA9FC        mov         eax,dword ptr [eax]
006EA9FE        mov         edx,0C0
006EAA03        call        @FillChar
006EAA08        mov         edi,dword ptr [esp]
006EAA0B        mov         edi,dword ptr [edi]
# 这里是版本修订号 可以看到数据是来自于esi的,而转换就是把数据转存到edi对应的地址里
# 实际上显示只有一个修订好, BLHeli Rev:32.6
# Main是32
006EAA0D        movzx       eax,byte ptr [esi+4];TBLHeli.FEep_FW_Main_Revision:byte
006EAA11        mov         byte ptr [edi],al
# 这个Sub是.6,二者组合起来形成了32.6的修订号
006EAA13        movzx       eax,byte ptr [esi+5];TBLHeli.FEep_FW_Sub_Revision:byte
006EAA17        mov         byte ptr [edi+1],al

OD动态调试看到,esi+4对应的地址值是20,那么也就是32

esi+5,对应的值也就是3C,对应的也就是60,所以版本号应该是32.60,只是UI显示的时候去掉了尾巴的0

# FEep_Layout_Revision 对应的显示是 HAKRC_35A,但是实际上这个值是2A
006EAA1A        movzx       eax,byte ptr [esi+6];TBLHeli.FEep_Layout_Revision:byte
006EAA1E        mov         byte ptr [edi+2],al
# 电压检测,对应的应该是low voltage protectin,这里读取到的是00
006EAA21        movzx       eax,byte ptr [esi+26];TBLHeli.FEep_Hw_Voltage_Sense_Capable:byte
006EAA25        mov         byte ptr [edi+30],al
# 电流检测 这个没找到对应的数据,这里读到的实际上是FF
006EAA28        movzx       eax,byte ptr [esi+27];TBLHeli.FEep_Hw_Current_Sense_Capable:byte
006EAA2C        mov         byte ptr [edi+31],al
006EAA2F        mov         dl,15
006EAA31        mov         eax,esi
# 这个不知道是干嘛的,看里面实现好像也是和电流有关系的
006EAA33        call        TBLHeli.IsParameterHardEnabled
006EAA38        test        al,al
006EAA3A>       je          006EAA5A
# led 0
006EAA3C        movzx       eax,byte ptr [esi+28];TBLHeli.FEep_Hw_LED_Capable_0:byte
006EAA40        mov         byte ptr [edi+32],al
# led 1
006EAA43        movzx       eax,byte ptr [esi+29];TBLHeli.FEep_Hw_LED_Capable_1:byte
006EAA47        mov         byte ptr [edi+33],al
# led 2
006EAA4A        movzx       eax,byte ptr [esi+2A];TBLHeli.FEep_Hw_LED_Capable_2:byte
006EAA4E        mov         byte ptr [edi+34],al
# led 3
006EAA51        movzx       eax,byte ptr [esi+2B];TBLHeli.FEep_Hw_LED_Capable_3:byte
006EAA55        mov         byte ptr [edi+35],al
006EAA58>       jmp         006EAA6A
# 不知道是什么全设置为了0

这里是led是否存在,00表示不存在,最多可以支持4个led,我这里只有3个,所以是01,02,03,00

006EAA5A        mov         byte ptr [edi+32],0
006EAA5E        mov         byte ptr [edi+33],0
006EAA62        mov         byte ptr [edi+34],0
006EAA66        mov         byte ptr [edi+35],0
# 这里是判定版本号,如果和29相等,就跳过这里的Note的配置,其实就是不支持音乐
006EAA6A        cmp         byte ptr [esi+6],29;TBLHeli.FEep_Layout_Revision:byte
006EAA6E>       jb          006EAA94
# 无阻尼模式,实际值01
006EAA70        movzx       eax,byte ptr [esi+2F];TBLHeli.FEep_Nondamped_Capable:byte
006EAA74        mov         byte ptr [edi+3F],al
# 这里是音乐的节拍速率 对应 Music Note Config,实际值为50,而我选的是长度为5,interval为0
006EAA77        movzx       eax,byte ptr [esi+20];TBLHeli.FEep_Note_Config:byte
006EAA7B        mov         byte ptr [edi+1C],al
006EAA7E        lea         edx,[edi+90]
# 这里的这个是音乐节拍的速度 对应 Startup Music Data
006EAA84        lea         eax,[esi+80];TBLHeli.FEep_Note_Array:TEep_Note_Array
006EAA8A        mov         ecx,30
006EAA8F        call        Move

这里应该是edx和eax,ecx都作为参数传入到Move里面,然后Move就是把eax地址的值搬运到edx中,搬运长度为ecx个,也就是0x30个字节

那么图中的高亮部分,就是实际音乐的节拍数组,下面是我的实际节拍,就会发现他是一一对应的,剩余的FF是没使用到的

但是分析到这里,我又对了一下发送的256数据,发现hex的内容和实际接收发送的数据对不上,而ESI地址中的数值又是谁赋进去的,需要找到这个,发现ESI是在CopyTo时EDX给进来的,然后edx又是ebp给进来的,实际上又是来自于ebp,从堆栈中取出来的。到这里就发现虽然数据可以解析了,但是解析的数据并不是原生的256字节,所以又要回去找读取的时候数据是怎么处理的(关键变成谁给0x2864D00或者0x289D000地址赋得值)

# 这里判定FEep_Layout_Revision<2C,所以跳转了
006EAA94        cmp         byte ptr [esi+6],2C;TBLHeli.FEep_Layout_Revision:byte
# 1.这里跳转了
006EAA98>       jb          006EAAB4
# 这里判断pwm频率是否大于最大或者小于最小值,是的话就不会设置这个值,不是的话才会读取这个pwm频率
006EAA9A        cmp         byte ptr [esi+2C],0FF;TBLHeli.FEep_Hw_Pwm_Freq_Min:byte
006EAA9E>       jae         006EAAB4
006EAAA0        cmp         byte ptr [esi+2D],0FF;TBLHeli.FEep_Hw_Pwm_Freq_Max:byte
006EAAA4>       jae         006EAAB4
# 读取pwm的最大最小频率
006EAAA6        movzx       eax,byte ptr [esi+2C];TBLHeli.FEep_Hw_Pwm_Freq_Min:byte
006EAAAA        mov         byte ptr [edi+36],al
006EAAAD        movzx       eax,byte ptr [esi+2D];TBLHeli.FEep_Hw_Pwm_Freq_Max:byte
006EAAB1        mov         byte ptr [edi+37],al
# 1.跳到这里 感觉像是一个if else if 的判断,这里FEep_Layout_Revision<2D 所以继续
006EAAB4        cmp         byte ptr [esi+6],2D;TBLHeli.FEep_Layout_Revision:byte
# 2.继续跳转
006EAAB8>       jb          006EAAC1
# 说白了这个电调就没有运动模式,所以这个设置不存在
006EAABA        movzx       eax,byte ptr [esi+2E];TBLHeli.FEep_SPORT_Capable:byte
006EAABE        mov         byte ptr [edi+3E],al
# 2.跳到这里继续
006EAAC1        lea         edx,[edi+40]
006EAAC4        lea         eax,[esi+30];TBLHeli.FEep_ESC_Layout:TESC_Layout
006EAAC7        mov         ecx,20
006EAACC        call        Move
# 把对应地址写入
006EAAD1        lea         edx,[edi+60]
# 这里加载了MCU的类型还是什么?
006EAAD4        lea         eax,[esi+50];TBLHeli.FEep_ESC_MCU:TESC_MCU
006EAAD7        mov         ecx,20
006EAADC        call        Move
# 这里应该是循环初始化 bl一开始等于4,后续结束循环需要看bl<0x1F
006EAAE1        mov         bl,4
# 感觉这里应该是有一个公用参数表,这里依次对各个参数进行初始化的样子
# 5.跳转到这里,下一步走到3,继续跳转
006EAAE3        mov         eax,ebx
006EAAE5        call        006DEB4C
006EAAEA        movzx       eax,al
006EAAED        mov         dword ptr [esp+4],eax
006EAAF1        cmp         dword ptr [esp+4],0FF
006EAAF9>       je          006EAB91
006EAAFF        mov         bp,0FFFF
006EAB03        mov         edx,ebx
006EAB05        mov         eax,esi
# 检测是否是有效参数
006EAB07        call        TBLHeli.IsParameterValid
006EAB0C        test        al,al
006EAB0E>       je          006EAB2B
006EAB10        mov         edx,ebx
006EAB12        mov         eax,esi
# 如果有效,那么获取参数的值
006EAB14        call        TBLHeli.GetParameterValue
006EAB19        mov         ebp,eax
006EAB1B        cmp         bl,0E
# 3.这里跳转
006EAB1E>       jne         006EAB62
006EAB20        test        bp,bp
006EAB23>       jbe         006EAB62
006EAB25        add         bp,18
006EAB29>       jmp         006EAB62
006EAB2B        mov         edx,ebx
006EAB2D        mov         eax,esi
# 这里判定参数是否存在,不是很明白什么意思
006EAB2F        call        TBLHeli.IsParameterExisting
006EAB34        test        al,al
006EAB36>       je          006EAB62
006EAB38        mov         eax,ebx
006EAB3A        sub         al,0F
006EAB3C>       je          006EAB48
006EAB3E        sub         al,6
006EAB40>       je          006EAB57
006EAB42        sub         al,3
006EAB44>       je          006EAB57
006EAB46>       jmp         006EAB62
006EAB48        mov         eax,esi
# 这里理解为 为了保护而故意强制使能某个参数,看了一眼里面的实现还是和电流相关的,这里应该没有这个问题,跳过吧。
006EAB4A        call        TBLHeli.IsCurrentProtectionFalselyHardEnabled
006EAB4F        test        al,al
006EAB51>       je          006EAB62
006EAB53        xor         ebp,ebp
006EAB55>       jmp         006EAB62
006EAB57        mov         edx,ebx
006EAB59        mov         eax,esi
# 相当于是说获取这个参数的默认值
006EAB5B        call        TBLHeli.GetParameterValueDefault
006EAB60        mov         ebp,eax
# 3.跳到这里继续
006EAB62        mov         eax,dword ptr [esp]
006EAB65        mov         eax,dword ptr [eax]
006EAB67        mov         edx,dword ptr [esp+4]
006EAB6B        mov         ecx,ebp
006EAB6D        and         cl,0FF
006EAB70        mov         byte ptr [eax+edx],cl
006EAB73        mov         eax,ebx
006EAB75        call        006DEB58
006EAB7A        cmp         al,1
# 4.这里跳转
006EAB7C>       jbe         006EAB91
006EAB7E        mov         eax,dword ptr [esp]
006EAB81        mov         eax,dword ptr [eax]
006EAB83        mov         edx,dword ptr [esp+4]
006EAB87        mov         ecx,ebp
006EAB89        shr         cx,8
006EAB8D        mov         byte ptr [eax+edx+1],cl
# 4.这里继续
006EAB91        inc         ebx
006EAB92        cmp         bl,1F
# 5.这里继续跳
006EAB95>       jne         006EAAE3
# 当上面3-5的循环完成以后,继续往下走
006EAB9B        lea         eax,[edi+80]
006EABA1        mov         cx,20
006EABA5        mov         edx,10
006EABAA        call        @FillChar
006EABAF        lea         edx,[edi+80]
# 这里才是ESC Name的赋值
006EABB5        lea         eax,[esi+70];TBLHeli.FEep_Name:TESC_Name
006EABB8        mov         ecx,10
006EABBD        call        Move
006EABC2        mov         al,1
006EABC4        pop         ecx
006EABC5        pop         edx
006EABC6        pop         ebp
006EABC7        pop         edi
006EABC8        pop         esi
006EABC9        pop         ebx
006EABCA        ret

密文详解

偏移 字节 参数名称 参数值(大端) 实际参数对应名称
0x0 1 FW_Main_Revision 0x20 BLHeli Rev 前缀
0x1 1 FW_Sub_Revision 0x3C BLHeli Rev 后缀
0x2 1 Layout_Revision 0x2A 没有实际对应的,但是作为内部识别码
0x3 1 Pgm_Direction 0x01 Motor Direction
0x4 1 Pgm_Rampup_Pwr 0x32 Rampup Power
0x5 1 Pgm_Pwm_Frequency 0x18 PWM Frequency
0x6 1 Pgm_Comm_Timing 0x10 Motor Timing
0x7 1 Pgm_Demag_Comp 0x02 Demag Compensation
0x8 2 Pgm_Min_Throttle 0x410 Minimum Throttle
0xA 2 Pgm_Center_Throttle 0x5DC Throttle Cal Enable
0xC 2 Pgm_Max_Throttle 0x7A8 Maximum Throttle
0xE 1 Pgm_Enable_Throttle_Cal 0x0 Throttle Cal Enable
0xF 1 Pgm_Temp_Prot 0x0 Temperature Protection
0x10 1 Pgm_Volt_Prot 0x0 Low Voltage Protection
0x11 1 Pgm_Curr_Prot 0x0 无效的
0x12 1 Pgm_Enable_Power_Prot 0x1 Low RPM Power Protect
0x13 1 Pgm_Brake_On_Stop 0x0 Brake On Stop
0x14 1 Pgm_Beep_Strength 0x28 Startup Beep Volume
0x15 1 Pgm_Beacon_Strength 0x50 Beacon/Signal Volume
0x16 2 Pgm_Beacon_Delay 0x0000 Beacon Delay
0x18 1 Pgm_LED_Control 0x0 LED Control
0x19 1 Pgm_Max_Acceleration 0x0 Maximum Acceleration
0x1A 1 Pgm_Nondamped_Mode 0x0 Non Damped Mode
0x1B 1 Pgm_Curr_Sense_Cal 0x64 无效的
0x1C 1 Note_Config 0x50 Music Note Config
0x1D 1 Pgm_Sine_Mode 0x0 Sine Modulation Mode
0x1E 1 Pgm_Auto_Tlm_Mode 0x0 Auto Telemetry
0x1F 1 Pgm_Stall_Prot 0xFF 无效的
0x20 1 Pgm_SBUS_Channel 0xFF 无效的
0x21 1 Pgm_SPORT_Physical 0xFF 无效的
0x30 1 Hw_Voltage_Sense_Capable 0x0  
0x31 1 Hw_Current_Sense_Capable 0x0  
0x32-0x35 4 Hw_LED_Capable_x 0-3 LED存在和顺序
0x3F 1 Nondamped_Capable 0x01  
0x40 32 ESC_Layout ESC Layout
0x60 16/32 ESC_CPU i_32*STM32F051X6 这里是ESC的CPU型号,这个值好像会被用来检测
0x80 16 ESC_Name Name
0x90 48 Note_Array Startup Music Data

到这里整体协议内容基本就都有了。还有几个相关的比如主控是什么型号,其实解密中也有,只是没用到所以没提

总体调用流程

actReadSetupExecute 按键act
 DoBtnReadSetup 按键具体操作
  ReadSetupAll 读取配置信息
   ReadDeviceSetupSection 这里是操作去读
    Send_cmd_DeviceReadBLHeliSetupSection 发送读取命令,执行后就拿到了256字节
    ReadSetupFromBinString 这里就是关键,解析读上来的字符串,然后赋值给了BLHeli的各个参数
     TBLHeli.Init 参数存储的对象初始化
     BLHeliSu.006EA090 解密开始的函数
      BLHeliSu.006E1B48 解密循环函数
       BLHeliSu.006E1960 内存可读的开始
        BLHeliSu.006D5A78 偏移操作的函数
    ReadSetupFromBinString 的后续内容会读取所有配置,然后给BLHeli对象赋值
    
    ReadDeviceActivationStatus 第二次读,由于和电调配置无关,具体数据没解析
    ReadDeviceUUID_Str 第三次读,由于和电调配置无关,具体数据没解析
    
   CopyTo 这里就开始涉及显示的东西,其实就是给参数赋值
    WriteSetupToString
    ReadSetupFromBinString
   SetupToControls 这里是把内容处理,显示到ui上
    OnSetupToControls 刷新UI

Summary

到此基本上BLH的加密就算可以正常破解了,其内容我也可以通过解析,拿到具体的配置了,工程中的问题已经可以解决了。

由于没有啥x86的汇编经验,相当于是纯新手直接打boss,花了好几天,走了不少弯路才把这个解决。

现在再想一下,如果IDR的信息可以导入OD,可以节省很多反复横跳的时间。

由于先入为主,觉得没名字的那种函数都不太重要所以没注意,就导致我前期找了好久解密函数。

总体大致花了十天左右才算是整个解决,前面卡住就卡了5天,基本没啥进度的程度。

如果后面还要再反编译什么,上手就更简单了,不会被这些东西迷惑了。

反编译的文章有点不好读,由于我全程都在反复对照,写的时候也是混在一起,比之前的顺序流程,这里经常逆序写注释,就很别扭,下次换个方式吧

Quote

https://www.52pojie.cn/thread-615448-1-1.html

http://www.youngroe.com/2019/07/01/Windows/delphi_reverse_summary/