3DNes字符串汉化不成功的问题定位解决

3DNes字符串汉化不成功的问题定位解决

这篇文章的起因是来自 shaokui123 在论坛的求助帖:

汉化字符大于原始长度(字符是主程序读取资源文件) - 『脱壳破解讨论求助区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

(原帖附件火绒报毒并成功杀毒,我在百度云盘传了一份杀过毒的以供练手:

链接:https://pan.baidu.com/s/1QD-ffT2LAalOoE7jXxaYQw 提取码:0fkp)

shaokui123 在汉化 3DNes 的过程中遇到两处汉化不成功的字符串(位于文件“\3DNes\3dnes_Data\level0”中):

1、文件偏移 0x1E7A0 处的字符串“Depth”

2、文件偏移 0x197B8 处的字符串“Open”

一、“Depth”汉化

需要汉化为两个字的 UTF8 编码汉字,占用 6 各字节

字符串会有长度信息和不带长度信息两种,前者根据长度信息读取相应位数的字符串,后者遇到0才停止读取

再看看字符串之前4个字节,“05”这个数字正好是字符串的长度,猜想有可能是长度信息,把它改成“06”试试,果然就成功了。这处比较简单,下一处就有点麻烦了

二、“Open”汉化

这个字符串藏得比较深,打开程序(注意勾选窗口化,否则全屏了),点击“Play”按键,再点击“Open”按键,下一界面出现的“Open”按键才是汉化不成功的目标字符串

这个字符串之前也有长度信息,但改过之后,整个按键的文字都不显示了,猜测还有地方限制了显示长度

这个软件是个 Unity 程序,试过用 AssetStudio 查找资源,也没有头绪,看来还得硬钢

首先想到的是要找到这个字符串出现的代码位置,再跟踪程序是如何处理这个字符串的,看看是否有线索

(“Open”在文件中出现两次,为了便于分析,把目标字符串改成了“1pen”)

1、先在内存中搜索“1pen”这串字符,找不到,改成搜索 Unicode,这次倒是搜到了,但这已经是转换过的,不是数据来源

考虑到字符串保存在文件“level0”中,要使用肯定要先读取

用调试器 x32dbg 载入主程序,在 API ReadFile 上下断点,运行至断下后回溯到用户代码

00B491BDFF15 00837301call dword ptr ds:[<ReadFile>]
00B491C38BF0mov esi,eax

发现读取了很多不同的文件,“level0”也是分段多次读取,怎样才准确定位到“1pen”读入的时机呢?

在地址 0xB491C3 下断点(此时 ReadFile 已执行完毕将文件读入内存),并编辑断点条件如下:

暂停条件:$result>0 (找到结果暂停)

命令:findallmem 0,"31 70 65 6E" (内存查找“1pen”)

命令条件:strstr(utf8(ebx),"level0" (文件名包含“level0”)

运行后一会儿成功断下,查看内存,字符串“1pen”已经读入

2、在字符串“1pen”上设置硬件访问断点,继续执行后断下,但断下的位置看不出端倪

我们来到“堆栈调用”标签中查看堆栈回溯,看到经过了多级调用才来到断点位置

地址返回到返回自大小注释
1142FACCB28852010CF6D824用户模块3dnes.UnwindUp1+4
1142FAF0A60CB700B288521C用户模块3dnes.CachedReader::Read+22
1142FB0CC72C5D00A60CB734用户模块3dnes.StreamedBinaryRead<0>::TransferSTLStyleArray+67
1142FB40C823A500C72C5D18用户模块3dnes.TransferField_NonArray<StreamedBinaryRead<0>,Converter_String>+2D
1142FB58FED40000C823A52C用户模块3dnes.Transfer_String<StreamedBinaryRead<0>,0>+15
1142FB84C8465100FED40064用户模块3dnes.ExecuteSerializationCommands<ProxyTransfer>+50
1142FBE8BF38EB00C8465124用户模块3dnes.TransferScriptingObject<StreamedBinaryRead<0> >+B1
1142FC0CCABBBC00BF38EBDC用户模块3dnes.MonoBehaviour::TransferEngineAndInstance<StreamedBinaryRead<0> >+5B
1142FCE8CA6E8B00CABBBCB4用户模块3dnes.SerializedFile::ReadObject+26C
1142FD9CC8794F00CA6E8BC4用户模块3dnes.PersistentManager::LoadFileCompletelyThreaded+2EB
1142FE60C859F100C8794F18用户模块3dnes.LoadSceneOperation::Perform+2AF
1142FE78C85A7B00C859F18用户模块3dnes.PreloadManager::Run+A1
1142FE80CC7D5D00C85A7B18用户模块3dnes.PreloadManager::Run+B
1142FE984BFA2900CC7D5D10系统模块3dnes.Thread::RunThreadWrapper+2D
1142FEA88A7A9E764BFA295C系统模块kernel32.@BaseThreadInitThunk@12+19
1142FF048A7A6E778A7A9E10系统模块ntdll.__RtlUserThreadStart+2F
1142FF14000000778A7A6E用户模块ntdll.__RtlUserThreadStart@8+1B

以上堆栈记录的调用都是公共函数,经过多次执行才来到我们设置的断点,我们现在需要准确定位到“1pen”这个字符串的处理流程

在堆栈调用中点击应用程序空间的每一级调用,返回地址的上一句调用 call 上下断点,从上至下注释好调用层级,设置中断条件为“0”(不中断只记录触发次数)

3、取消步骤 2 的硬件断点,重启程序,执行至步骤 1 的断点,在字符串“1pen”上设置硬件访问断点,继续执行至断下

此时查看断点清单,1-8 级调用均有命中,并记录下了命中次数,先取消未命中断点和步骤 1 的断点

然后用这个命中次数为调用 call 设置点断条件(比如 1 级命中 4156 次设置断点条件 $breakpointcounter==.4156)

这样设置后确保调用 call 断下的时候正在处理目标字符串,设置完后我的机器上断点清单如下:

地址反汇编命中摘要(前面数字是注释的调用层级)
00A60CB2call <3dnes.public: void __thiscall StreamedBinaryRead<0>::ReadDirect(void *, int)>11142, 暂停条件($breakpointcounter==.1114)
00B2884Dcall <3dnes._memcpy>41561, 暂停条件($breakpointcounter==.4156)
00BF38E6call <3dnes.void __cdecl TransferScriptingObject>317, 暂停条件($breakpointcounter==.31)
00C72C58call <3dnes.public: void __thiscall StreamedBinaryRead<0>::TransferSTLStyleArray>  693, 暂停条件($breakpointcounter==.69)
00C823A0call <3dnes.void __cdecl TransferField_NonArray>694, 暂停条件($breakpointcounter==.69)
00C8464Ccall <3dnes.void __cdecl ExecuteSerializationCommands>316, 暂停条件($breakpointcounter==.31)
00CABBBAcall edx16318, 暂停条件($breakpointcounter==.1631)
00FED3FEcall eax6785, 暂停条件($breakpointcounter==.678)

4、接着我们来看看将字符串长度改变会发生什么,将字符串长度信息由“04”改为“06”,字符串“1pen”改为“1penen”

重新载入程序,一路执行,发现执行到第 1 级调用 0xB2884D 的 call <3dnes._memcpy> 时出现问题了

本该内存拷贝复制的目标字符串没有出现,是哪里出了问题呢?

重启程序,到第 2 级调用 call 的时候 F7 单步进入第 1 级段首

00B2883055push ebp
00B288318BECmov ebp,esp
00B2883383EC 08sub esp,0x8
00B2883653push ebx
00B288378B5D 0Cmov ebx,dword ptr ss:[ebp+0xC]字符串长度
00B2883A57push edi
00B2883B8BF9mov edi,ecxedi指向字符串地址
00B2883D8B07mov eax,dword ptr ds:[edi]字符串地址
00B2883F8D0C18lea ecx,dword ptr ds:[eax+ebx]字符串最后位+1的地址
00B288423B4F 08cmp ecx,dword ptr ds:[edi+0x8]
00B2884577 18ja 3dnes.B2885F改过会跳过
00B288478B55 08mov edx,dword ptr ss:[ebp+0x8]
00B2884A53push ebx
00B2884B50push eax
00B2884C52push edx
00B2884DE8 2E6D5A00call <3dnes._memcpy>1
00B2885283C4 0Cadd esp,0xC
00B28855011Fadd dword ptr ds:[edi],ebx
00B288575Fpop edi
00B288585Bpop ebx
00B288598BE5mov esp,ebp
00B2885B5Dpop ebp
00B2885CC2 0800ret 0x8
00B2885F56push esi

单步执行下来,执行到 0xB28842 将字符串最后位+1 的地址和 ds:[edi+0x8] 保存的地址进行比较

ds:[edi+0x8] 保存的地址指向的是“1penen”的第 5 位,刚好是我们修改增加后的内容,这里很可疑

我们将 ds:[edi+0x8] 保存的地址增加 2,即指向“1penen”地址+6 的地方,继续执行后成功显示了

5、现在我们要找到 ds:[edi+0x8] 的数据来源,按数据产生的流程当然要从最高层级开始分析

首先在第 8 级调用 call 的段首设置条件断点,断点条件跟第 8 级调用 call 一样

然后重启程序,执行到第 8 级调用 call 的段首断下,此时“1penen”已经在内存中

找到“1penen”地址,因为步骤 4 中错误的 ds:[edi+0x8] 地址为“1penen”地址+4,我们在内存中搜索这个地址

现在还找不到这个地址,因为还没有开始处理(注意这个地址在内存中是倒序存放的(小端存储))

我们单步向下执行,遇到 call 步过,然后搜索一下内存是否出现上面的错误地址

执行到 0xCABB63 call <3dnes.public: void __thiscall CachedReader::InitRead 后目标地址出现了

6、继续向下分析“1penen”地址+4 的来源,重启程序,执行到  0xCABB63 的时候 F7 单步进入分析

00B286538B4D 10mov ecx,dword ptr ss:[ebp+0x10]定位数据,原为0x104,修改为6位应为0x106
00B286568D140Blea edx,dword ptr ds:[ebx+ecx]
00B286598B4E 0Cmov ecx,dword ptr ds:[esi+0xC]
00B2865C8956 1Cmov dword ptr ds:[esi+0x1C],edx
00B2865F8D7E 08lea edi,dword ptr ds:[esi+0x8]
00B2866257push edi
00B286638D56 04lea edx,dword ptr ds:[esi+0x4]
00B28666895E 18mov dword ptr ds:[esi+0x18],ebx
00B2866952push edx
00B2866A8946 10mov dword ptr ds:[esi+0x10],eax
00B2866D8B09mov ecx,dword ptr ds:[ecx]
00B2866F50push eax
00B286708BC1mov eax,ecx
00B286728B4E 0Cmov ecx,dword ptr ds:[esi+0xC]
00B286758B40 08mov eax,dword ptr ds:[eax+0x8]
00B28678FFD0call eax
00B2867A8B4E 14mov ecx,dword ptr ds:[esi+0x14]
00B2867D0FAF4E 10imul ecx,dword ptr ds:[esi+0x10]
00B286818B46 1Cmov eax,dword ptr ds:[esi+0x1C]
00B286842BC1sub eax,ecx
00B286860346 04add eax,dword ptr ds:[esi+0x4]字符串最后位+1地址(“1penen”地址+4)

执行到 0xB28686 的时候出现了目标地址,经分析,这个地址是用 0xB28653 的数据经过计算得来

0xB28653 的数据是个偏移,与载入内存的地址计算得出绝对地址,我们姑且称它为“定位数据”

这个“定位数据”来自上级 call 的第 4 个参数,还得回到上一级来分析

(这里的分析没有什么好讲的,纯粹是硬啃汇编指令,结合动态分析会更容易一些)

7、重启程序来到第 8 级调用 call 的段首,从 0xCABB63 开始向上看

00CAB97CE8 CFC5FFFFcall <3dnes.struct std::pair<__int64, struct SerializedFile::ObjectInfo> const * __cdecl std::_Lower_bound<struct std::pair<__int64, struct SerializedFile::ObjectInfo> const *, __int64, int, class vector_map<__int64, struct SerializedFile::ObjectInfo, struct std::les>读入字符串和定位数据
00CAB98183C4 14add esp,0x14
00CAB9843BC6cmp eax,esi
00CAB98674 15je 3dnes.CAB99D
00CAB9888B55 0Cmov edx,dword ptr ss:[ebp+0xC]
00CAB98B3B50 04cmp edx,dword ptr ds:[eax+0x4]
00CAB98E7C 0Djl 3dnes.CAB99D
00CAB9907F 07jg 3dnes.CAB999
00CAB9928B4D 08mov ecx,dword ptr ss:[ebp+0x8]
00CAB9953B08cmp ecx,dword ptr ds:[eax]
00CAB99772 04jb 3dnes.CAB99D
00CAB9998BF8mov edi,eax定位数据=[eax+c]
00CAB99BEB 02jmp 3dnes.CAB99F
00CAB99D8BFEmov edi,esi
00CAB99F3BFEcmp edi,esi
00CAB9A10F84 59020000je 3dnes.CABC00
00CAB9A78D47 10lea eax,dword ptr ds:[edi+0x10]
00CAB9AA50push eax
00CAB9AB8BCBmov ecx,ebx
00CAB9ADE8 DEE7FFFFcall <3dnes.public: class SerializedFile::Type & __thiscall std::map<int, class SerializedFile::Type, struct std::less<int>, class std::allocator<struct std::pair<int const, class SerializedFile::Type>>>::operator[](int const &)>
00CAB9B2807B 34 00cmp byte ptr ds:[ebx+0x34],0x0
00CAB9B68B75 20mov esi,dword ptr ss:[ebp+0x20]
00CAB9B98945 FCmov dword ptr ss:[ebp-0x4],eax
00CAB9BC74 72je 3dnes.CABA30
00CAB9BE8378 28 FFcmp dword ptr ds:[eax+0x28],0xFFFFFFFF
00CAB9C275 6Cjne 3dnes.CABA30
00CAB9C48B56 08mov edx,dword ptr ds:[esi+0x8]
00CAB9C7C1EA 15shr edx,0x15
00CAB9CA3B57 10cmp edx,dword ptr ds:[edi+0x10]
00CAB9CD75 61jne 3dnes.CABA30
00CAB9CF68 DF060000push 0x6DF
00CAB9D468 70BF7301push <3dnes."">
00CAB9D96A 10push 0x10
00CAB9DB6A 4Bpush 0x4B
00CAB9DD6A 30push 0x30
00CAB9DFE8 3C83E9FFcall <3dnes.void * __cdecl operator new(unsigned int, enum MemLabelIdentifier, int, char const *, int)>
00CAB9E483C4 14add esp,0x14
00CAB9E785C0test eax,eax
00CAB9E974 0Eje 3dnes.CAB9F9
00CAB9EB6A 4Bpush 0x4B
00CAB9ED8BC8mov ecx,eax
00CAB9EFE8 0C130000call <3dnes.public: __thiscall TypeTree::TypeTree(enum MemLabelIdentifier)>
00CAB9F48945 20mov dword ptr ss:[ebp+0x20],eax
00CAB9F7EB 07jmp 3dnes.CABA00
00CAB9F9C745 20 00000000mov dword ptr ss:[ebp+0x20],0x0
00CABA008B43 30mov eax,dword ptr ds:[ebx+0x30]
00CABA038B4D 20mov ecx,dword ptr ss:[ebp+0x20]
00CABA060D 00200000or eax,0x2000
00CABA0B50push eax
00CABA0C51push ecx
00CABA0D56push esi
00CABA0EE8 0D0B0000call <3dnes.void __cdecl GenerateTypeTree(class Object &, class TypeTree *, enum TransferInstructionFlags)>
00CABA138B55 20mov edx,dword ptr ss:[ebp+0x20]
00CABA168B4D FCmov ecx,dword ptr ss:[ebp-0x4]
00CABA1983C4 0Cadd esp,0xC
00CABA1C52push edx
00CABA1DE8 3EB9FFFFcall <3dnes.public: void __thiscall SerializedFile::Type::CompareAgainstNewType(class TypeTree *)>
00CABA228B45 20mov eax,dword ptr ss:[ebp+0x20]
00CABA256A 4Bpush 0x4B
00CABA2750push eax
00CABA28E8 93CEFFFFcall <3dnes.void __cdecl delete_internal<class TypeTree>(class TypeTree *, enum MemLabelIdentifier)>
00CABA2D83C4 08add esp,0x8
00CABA308B43 30mov eax,dword ptr ds:[ebx+0x30]
00CABA3383C8 01or eax,0x1
00CABA36807B 2C 00cmp byte ptr ds:[ebx+0x2C],0x0
00CABA3A8945 0Cmov dword ptr ss:[ebp+0xC],eax
00CABA3D74 08je 3dnes.CABA47
00CABA3F0D 00020000or eax,0x200
00CABA448945 0Cmov dword ptr ss:[ebp+0xC],eax
00CABA47837D 10 01cmp dword ptr ss:[ebp+0x10],0x1
00CABA4B75 08jne 3dnes.CABA55
00CABA4D0D 00008000or eax,0x800000
00CABA528945 0Cmov dword ptr ss:[ebp+0xC],eax
00CABA558B4D 14mov ecx,dword ptr ss:[ebp+0x14]
00CABA5851push ecx
00CABA598BCEmov ecx,esi
00CABA5BE8 F05CDCFFcall <3dnes.private: void __thiscall Object::SetIsPersistent(bool)>
00CABA608B43 10mov eax,dword ptr ds:[ebx+0x10]
00CABA630347 08add eax,dword ptr ds:[edi+0x8]
00CABA668B4D FCmov ecx,dword ptr ss:[ebp-0x4]
00CABA698945 20mov dword ptr ss:[ebp+0x20],eax
00CABA6C33C0xor eax,eax
00CABA6E3941 24cmp dword ptr ds:[ecx+0x24],eax
00CABA710F84 AD000000je 3dnes.CABB24
00CABA773941 28cmp dword ptr ds:[ecx+0x28],eax
00CABA7A0F84 A4000000je 3dnes.CABB24
00CABA808D8D 3CFFFFFFlea ecx,dword ptr ss:[ebp-0xC4]
00CABA86E8 850DFFFFcall <3dnes.public: __thiscall SafeBinaryRead::SafeBinaryRead(void)>
00CABA8B8B55 FCmov edx,dword ptr ss:[ebp-0x4]
00CABA8E8B42 24mov eax,dword ptr ds:[edx+0x24]
00CABA918BCEmov ecx,esi
00CABA938945 B8mov dword ptr ss:[ebp-0x48],eax
00CABA96C745 BC 00000000mov dword ptr ss:[ebp-0x44],0x0
00CABA9DE8 DE5DDCFFcall <3dnes.public: enum MemLabelIdentifier __thiscall Object::GetMemoryLabel(void) const>
00CABAA28B4D 0Cmov ecx,dword ptr ss:[ebp+0xC]
00CABAA58B57 0Cmov edx,dword ptr ds:[edi+0xC]
00CABAA850push eax
00CABAA98B45 20mov eax,dword ptr ss:[ebp+0x20]
00CABAAC51push ecx
00CABAAD52push edx
00CABAAE50push eax
00CABAAF8D4D B8lea ecx,dword ptr ss:[ebp-0x48]
00CABAB251push ecx
00CABAB38D8D 3CFFFFFFlea ecx,dword ptr ss:[ebp-0xC4]
00CABAB9E8 620AFFFFcall <3dnes.public: class CachedReader & __thiscall SafeBinaryRead::Init(class TypeTreeIterator const &, int, int, enum TransferInstructionFlags, enum MemLabelIdentifier)>
00CABABE8B57 0Cmov edx,dword ptr ds:[edi+0xC]
00CABAC18B4D 20mov ecx,dword ptr ss:[ebp+0x20]
00CABAC452push edx
00CABAC58B53 74mov edx,dword ptr ds:[ebx+0x74]
00CABAC851push ecx
00CABAC952push edx
00CABACA8BC8mov ecx,eax
00CABACC8945 10mov dword ptr ss:[ebp+0x10],eax
00CABACFE8 5CCBE7FFcall <3dnes.public: void __thiscall CachedReader::InitRead(class CacheReaderBase &, unsigned int, unsigned int)>
00CABAD48B06mov eax,dword ptr ds:[esi]
00CABAD68B50 14mov edx,dword ptr ds:[eax+0x14]
00CABAD98BCEmov ecx,esi
00CABADBFFD2call edx
00CABADD8B06mov eax,dword ptr ds:[esi]
00CABADF8B50 40mov edx,dword ptr ds:[eax+0x40]
00CABAE28D8D 3CFFFFFFlea ecx,dword ptr ss:[ebp-0xC4]
00CABAE851push ecx
00CABAE98BCEmov ecx,esi
00CABAEBFFD2call edx
00CABAED8B4D 10mov ecx,dword ptr ss:[ebp+0x10]
00CABAF0E8 BBCBE7FFcall <3dnes.public: unsigned int __thiscall CachedReader::End(void)>
00CABAF52B45 20sub eax,dword ptr ss:[ebp+0x20]
00CABAF88B4F 0Cmov ecx,dword ptr ds:[edi+0xC]
00CABAFB3BC1cmp eax,ecx
00CABAFD76 0Fjbe 3dnes.CABB0E
00CABAFF56push esi
00CABB0050push eax
00CABB010FBF47 14movsx eax,word ptr ds:[edi+0x14]
00CABB0551push ecx
00CABB06E8 35D7FFFFcall <3dnes.OutOfBoundsReadingError>
00CABB0B83C4 0Cadd esp,0xC
00CABB0E8B45 1Cmov eax,dword ptr ss:[ebp+0x1C]
00CABB118D8D 3CFFFFFFlea ecx,dword ptr ss:[ebp-0xC4]
00CABB17C600 01mov byte ptr ds:[eax],0x1
00CABB1AE8 510DFFFFcall <3dnes.public: __thiscall SafeBinaryRead::~SafeBinaryRead(void)>
00CABB1FE9 C1000000jmp 3dnes.CABBE5
00CABB248945 C0mov dword ptr ss:[ebp-0x40],eax
00CABB278945 C4mov dword ptr ss:[ebp-0x3C],eax
00CABB2A8945 C8mov dword ptr ss:[ebp-0x38],eax
00CABB2D8D4D CClea ecx,dword ptr ss:[ebp-0x34]
00CABB303843 2Ccmp byte ptr ds:[ebx+0x2C],al
00CABB3375 4Ajne 3dnes.CABB7F
00CABB35E8 66C7E7FFcall <3dnes.public: __thiscall CachedReader::CachedReader(void)>
00CABB3A8BCEmov ecx,esi
00CABB3CE8 3F5DDCFFcall <3dnes.public: enum MemLabelIdentifier __thiscall Object::GetMemoryLabel(void) const>
00CABB418B57 0Cmov edx,dword ptr ds:[edi+0xC]定位数据
00CABB448B4D 0Cmov ecx,dword ptr ss:[ebp+0xC]
00CABB478945 C8mov dword ptr ss:[ebp-0x38],eax
00CABB4A8B43 10mov eax,dword ptr ds:[ebx+0x10]
00CABB4D0347 08add eax,dword ptr ds:[edi+0x8]
00CABB5052push edx定位数据
00CABB51894D C0mov dword ptr ss:[ebp-0x40],ecx
00CABB548B4B 74mov ecx,dword ptr ds:[ebx+0x74]
00CABB5750push eax
00CABB5851push ecx
00CABB598D4D CClea ecx,dword ptr ss:[ebp-0x34]
00CABB5CC745 C4 00000000mov dword ptr ss:[ebp-0x3C],0x0
00CABB63E8 C8CAE7FFcall <3dnes.public: void __thiscall CachedReader::InitRead(class CacheReaderBase &, unsigned int, unsigned int)>出现字符串最后位+1地址

0xCABB63 第 4 个参数来自 0xCABB50,0xCABB50 的数据来自 0xCABB41,0xCABB41 的数据来自 0xCAB999

我们先执行到 0xCAB999,看看 eax 指向的地址存放的是什么

[eax+c] 的地址存放的就是我们要找的定位数据,将此处“04”改为“06”,结果是意料之中的

8、eax 是 0xCAB97C 的返回值,理论上应该进入这个 call 进一步分析来源

但我们有更简单的方法,那就是:猜!!!

从前后结构来看 eax 指向的这块数据挺有规律,就像一张表,我们先到文件里找找看

在文件“level0”中搜索“04 01 00 00”这一串数据,搜到很多项,我们不断扩大特征码来缩小范围

搜索到“04 01 00 00 FC FF FF FF 72 00 1F 00 00 00 00 00”的时候,再扩大特征码就搜不到数据了

我们看看搜到的数据,再与程序内存数据比较一下

第一处搜到的数据后面跟着“25 03 00 00”,内存中也有这串数据,只不过中间多了“00 00 00 00”

向后看看,下一项数据也能对上,这里很可能就是关键的数据

不管它,先改改看,改完运行,结果很完美,成功找到了关键数据位置

最终修改之处有三,分别是字符串长度、字符串字符数据及显示长度,前后对比如下:

后记:

调试过程中的一些办法(非明文字符串的搜索、关键流程的准确定位)是我在平时调试过程中自己摸索出来的,在这里抛砖引玉,如果有更好更快捷的方法不妨提出来大家共同进步。字符串是很多程序执行流程的关键提示,越来越多的程序将字符串做了加密,导致内存中搜索不到,但只要显示了,它肯定得先解密,用完再销毁,我们先粗略定位,再通过 x32dbg 灵活的条件断点(复杂一点的需要编写脚本),最终很可能就找到关键位置了,我用这个办法在不同软件中也找到过加密字符串,最终实现了自己想要的目标。x32dbg 是个很强大的工具,我也一直在学习中,多用、善用工具,可以大大提高自己的工作效率。

下面是我在这次分析过程中写的一个脚本,这个脚本初始的设想是用于定位比特流的处理过程,具体方法从头开始执行程序,遇到 call 就检测目标比特流,检测到目标出现就记录日志并进入这个 call 继续向下寻找,最后查看日志就可以看到这个比特流处理的整个执行流程,从而分析到程序的关键处理流程。这个脚本最终在这次分析中没有发挥作用,因为写得匆忙,仅仅是一个初步的思路,也许可以应付一些简单的程序,还有没考虑到的地方(如线程等),可能还有 bug 需要修改,这里也分享出来供大家参考,希望各路高手能提供更好更完善的分析思路。

$addr=0

reload:

init "D:\Down\汉化字符大于原始长度(字符是主程序读取资源文件)\3DNes\3dnes.exe"

cmp $addr,0

je cont

g $addr

cont:

tocnd "dis.iscall(cip)"

$addr=cip

step

findallmem 0,"31 70 65 6E"

cmp $result,0

je cont

log "found pattern at "{$addr}

jmp reload

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值