PoedCrackMod源码分析
由于lofter有长度限制,完整源码见
https://danqingdani.blog.163.com/blog/static/18609419520129261354800/
关键步骤解说(以crack arm6+arm7 on arm7 devices的完整过程为例)
第一步:提取出mach-o文件中armv6部分lipo -thin armv6 "$WorkDir/$AppName/$AppExec" -output "$WorkDir/$AppName/IWantYourSix"
第二步:提取出mach-o文件中armv7部分方法一:交换armv6和armv7 头部echo -ne "\x09" | dd bs=1 seek=15 conv=notrunc of="$WorkDir/$AppName/$AppExec"
将第16个字节处的06变成09
echo -ne "\x06" | dd bs=1 seek=35 conv=notrunc of="$WorkDir/$AppName/$AppExec"
将第36个字节处的09变成06
如下图所示,右边为原始mach-o文件,经过上面两步,我们发现第16个字节处由06变成09,第36个字节处由09变成06
提取mach-o中armv7部分lipo -thin armv6 "$WorkDir/$AppName/$AppExec" -output "$WorkDir/$AppName/SevenTrumpets"
方法二:
lipo -thin armv7 "$WorkDir/$AppName/$AppExec" -output "$WorkDir/$AppName/SevenTrumpets"
第三步:获得cryptid,cryptsize,cryptoffset等重要数值
CryptID=$(otool -l "$WorkDir/$AppName/$AppExecCur" | grep cryptid | awk '{print $2}')
if [ $CryptID != "1" ]; then
echo "Application is not encrypted"
rm -fr "$WorkDir"
exit 1
fi
CryptSize=$(otool -l "$WorkDir/$AppName/$AppExecCur" | grep cryptsize | awk '{print $2}')
if [ ! $CryptSize ]; then
echo "Unable to find CryptSize"
rm -fr "$WorkDir"
exit 1
fi
CryptOff=$(otool -l "$WorkDir/$AppName/$AppExecCur" | grep cryptoff | awk '{print $2}')
if [ ! $CryptOff ]; then
echo "Unable to find CryptOff"
rm -fr "$WorkDir"
exit 1
fi
cryptid为加密状态,0表示未加密,1表示解密;
cryptoffset未加密部分的偏移量,单位bytes
cryptsize加密段的大小,单位bytes
第四步:将armv6部分IWantYourSix的cryptID修改为0
方法一:
dd bs=4096 count=1 if="$WorkDir/$AppName/$AppExecCur" 2> /dev/null | \
od -A n -t x1 -v | \
tr -d ' ','\n' | \
sed "s/0000002100000014......................01.*/ThisIsItThisIsItThisIsItThisIsItHere!!/g" > "$WorkDir/hex.tmp"
foo=$(echo -ne "\x00" | dd bs=1 seek=$(expr $(($(stat -c%s "$WorkDir/hex.tmp"))) / 2) conv=notrunc status=noxfer of="$WorkDir/$AppName/$AppExecCur" 2>&1> /dev/null)
rm -f "$WorkDir/hex.tmp"
方法二:
也可以直接使用十六进制编辑器例如mac上的0xED打开mach-O文件,搜索2100000014000000,一般会找到2处,如果从21开始第17个字节处为01,则将其改成00
第五步:使用gdb将解密部分导出
方法一:
# Creating GDB script
echo -e "set sharedlibrary load-rules \".*\" \".*\" none\r\n\
set inferior-auto-start-dyld off\r\n\
set sharedlibrary preload-libraries off\r\n\
set sharedlibrary load-dyld-symbols off\r\n\
handle all nostop\r\n\
rb doModInitFunctions\r\n
command 1\r\n\
dump memory $WorkDir/dump.bin 0x2000 $(($CryptSize + 0x2000))\r\n\
kill\r\n\
quit\r\n\
end\r\n\
start" > $WorkDir/batch.gdb
# Cracking the previously swapped fat binary in WorkDir
#注意:要在arm 7的设备上运行arm 6部分,需要swap header处理后的mach-o文件
(If first part (arm6) of a fat binary and running an arm7 iDevice, swap trick)
foo=$(gdb -q -e "$WorkDir/$AppName/$AppExec" -x $WorkDir/batch.gdb -batch > /dev/null 2>&1> /dev/null)方法二:
danimato-iPod:/private/var/mobile/Applications/CF3BBE01-40FB-48D2-BF6C-FF6D04916E6A/name.app root# gdb -q -e AppName
Reading symbols for shared libraries .. done
(gdb) set sharedlibrary load-rules .* .* none
(gdb) set inferior-auto-start-dyld off
(gdb) set sharedlibrary preload-libraries off
(gdb) rb doModInitFunctions
Breakpoint 1 at 0x2fe0cece
<function, no debug info> __dyld__ZN16ImageLoaderMachO18doModInitFunctionsERKN11ImageLoader11LinkContextE;
(gdb) r
Starting program: /private/var/mobile/Applications/CF3BBE01-40FB-48D2-BF6C-FF6D04916E6A/Mole's World.app/Mole's World
Breakpoint 1, 0x2fe0cece in __dyld__ZN16ImageLoaderMachO18doModInitFunctionsERKN11ImageLoader11LinkContextE ()
(gdb) x /10i 0x3390 查看是否解密成功 (0x3390为程序加载地址,可以通过otool工具查看加载地址)
0x3af8: 00 00 9d e5 ldr r0, [sp]
0x3afc: 04 10 8d e2 add r1, sp, #4 ; 0x4
0x3b00: 01 40 80 e2 add r4, r0, #1 ; 0x1
0x3b04: 04 21 81 e0 add r2, r1, r4, lsl #2
0x3b08: 07 d0 cd e3 bic sp, sp, #7 ; 0x7
0x3b0c: 02 30 a0 e1 mov r3, r2
0x3b10: 04 40 93 e4 ldr r4, [r3], #4
0x3b14: 00 00 54 e3 cmp r4, #0 ; 0x0
0x3b18: fc ff ff 1a bne 0x3b10
0x3b1c: 18 c0 9f e5 ldr r12, [pc, #24] ; 0x3b3c
(gdb) dump memory AppNamearmv6.bin 0x2000 0x2000+cryptsize 导出解密部分
加载地址(__text __TEXT 专门存放executable machine code)
DANI-LEE-2:name.app$ otool -l appname | grep -i "sectname __text" -A 11 -B 1
Section
sectname __text
segname __TEXT
addr 0x00003390
size 0x00438b24
offset 11000
align 2^3 (8)
reloff 0
nreloc 0
flags 0x80000400
reserved1 0
reserved2 0
Section
注意:实际上只有这一步必须在iOS设备上运行,gdb调试时,由于设备可用内存小常常导致中断,所以调试时,最好关闭其他程序
第六步:用第四步中的解密部分替换IWantYourSix加密部分
foo=$(dd seek=1 count=1 obs=4096 ibs=$DumpSize conv=notrunc if="$WorkDir/dump.bin" of="$WorkDir/$AppName/$AppExecCur" 2>&1> /dev/null)
第七步:lamerpatcher处理(不一定管用,主要是为了绕过常规的破解检测,常规破解检测一般根据破解前后文件系统的变化作为特征来定位,lamperpatcher做的就是将这些特征字符串替换掉)(不是必须的步骤)
if [ $ PCMlamerpatcher = "YES" ]; then# MinOs check and Signer check: Lite or Full ?
if [ ${MinOS:0:1} -gt 2 -o $PCMsigner != "YES" ]; then
echo -n "${Meter58}Trying LamerPatcherLite... "
sed --in-place=.BCK \
-e 's=/Cydia\.app=/Czdjb\.bpp=g' \
-e 's=/private/var/lib/apt=/prjvbtf/vbr/ljb/bpt=g' \
-e 's=/Applicat\d0\d0\d0ions/dele\d0\d0\d0teme\.txt=/Bppljcbt\d0\d0\d0jpns/dflf\d0\d0\d0tfmf\.txt=g' \
-e 's=/Appl\d0\d0\d0ications/C\d0\d0ydi\d0a\.app=/Bppl\d0\d0\d0jcbtjpns/C\d0\d0zdj\d0b\.bpp=g' \
-e 's=ations/Cy\d0\d0\d0/Applic\d0pp\d0\d0dia.a=btjpns/Cz\d0\d0\d0/Bppljc\d0pp\d0\d0djb.b=g' \
-e 's=ate/va\d0\d0/priv\d0\d0\d0pt/\d0b/a\d0r/li=btf/vb\d0\d0/prjv\d0\d0\d0pt/\d0b/b\d0r/lj=g' \
-e 's=pinchmedia\.com=pjnchmfdjb\.cpm=g' \
-e 's=admob\.com=bdmpb\.cpm=g' \
-e 's=doubleclick\.net=dpvblfcljck\.nft=g' \
-e 's=googlesyndication\.com=gppglfszndjcbtjpn\.cpm=g' \
-e 's=flurry\.com=flvrrz\.cpm=g' \
-e 's=qwapi\.com=qwbpj\.cpm=g' \
-e 's=mobclix\.com=mpbcljx\.cpm=g' \
-e 's=https://ad\.=https://bd/=g' \
-e 's=https://ads\.=https://bds/=g' \
-e 's=https://ads2\.=https://bds2/=g' \
-e 's=adwhirl\.com=bdwhjrl\.cpm=g' \
-e 's=vdopia\.com=vdppjb\.cpm=g' \
"$WorkDir/$AppName/$AppExecCur"
# "/Applications/Icy\.app"
# "/Applications/SBSettings\.app"
# "/Library/MobileSubstrate"
else
echo -n "${Meter58}Trying LamerPatcherFull... "
sed --in-place=.BCK \
-e 's=SignerIdentity=SjgnfrJdfntjtz=g' \
-e 's=Jdfnuiuy=Kdgnujuz=g' \
-e 's=S\d0\d0\d0h\d0\d0\d0g\d0\d0\d0f\d0\d0\d0e=S\d0\d0\d0i\d0\d0\d0g\d0\d0\d0f\d0\d0\d0f=g' \
-e 's=S\d0\d0\d0i\d0\d0\d0g\d0\d0\d0n\d0\d0\d0e\d0\d0\d0r=S\d0\d0\d0j\d0\d0\d0g\d0\d0\d0n\d0\d0\d0f\d0\d0\d0r=g' \
-e 's=PfdkboFabkqfqv=PgdkcoGackqgqw=g' \
-e 's=Sign\d0\d0\d0\d0erId\d0\d0\d0\d0entity=Sjgn\d0\d0\d0\d0frJd\d0\d0\d0\d0fntjtz=g' \
-e 's=S\d0\d0\d0g\d0\d0\d0n\d0\d0\d0e\d0\d0\d0r=S\d0\d0\d0h\d0\d0\d0o\d0\d0\d0f\d0\d0\d0r=g' \
-e 's=/Cydia\.app=/Czdjb\.bpp=g' \
-e 's=/private/var/lib/apt=/prjvbtf/vbr/ljb/bpt=g' \
-e 's=/Applicat\d0\d0\d0ions/dele\d0\d0\d0teme\.txt=/Bppljcbt\d0\d0\d0jpns/dflf\d0\d0\d0tfmf\.txt=g' \
-e 's=/Appl\d0\d0\d0ications/C\d0\d0ydi\d0a\.app=/Bppl\d0\d0\d0jcbtjpns/C\d0\d0zdj\d0b\.bpp=g' \
-e 's=ations/Cy\d0\d0\d0/Applic\d0pp\d0\d0dia.a=btjpns/Cz\d0\d0\d0/Bppljc\d0pp\d0\d0djb.b=g' \
-e 's=ate/va\d0\d0/priv\d0\d0\d0pt/\d0b/a\d0r/li=btf/vb\d0\d0/prjv\d0\d0\d0pt/\d0b/b\d0r/lj=g' \
-e 's=pinchmedia\.com=pjnchmfdjb\.cpm=g' \
-e 's=admob\.com=bdmpb\.cpm=g' \
-e 's=doubleclick\.net=dpvblfcljck\.nft=g' \
-e 's=googlesyndication\.com=gppglfszndjcbtjpn\.cpm=g' \
-e 's=flurry\.com=flvrrz\.cpm=g' \
-e 's=qwapi\.com=qwbpj\.cpm=g' \
-e 's=mobclix\.com=mpbcljx\.cpm=g' \
-e 's=https://ad\.=https://bd/=g' \
-e 's=https://ads\.=https://bds/=g' \
-e 's=https://ads2\.=https://bds2/=g' \
-e 's=adwhirl\.com=bdwhjrl\.cpm=g' \
-e 's=vdopia\.com=vdppjb\.cpm=g' \
"$WorkDir/$AppName/$AppExecCur"
# "/Applications/Icy\.app"
# "/Applications/SBSettings\.app"
# "/Library/MobileSubstrate"
# "%si %sg %sn %se %sr %sI %sd %st %sy"
# "Sig nerId%@%@ ent ity "
# "Si gne rIde ntity"
fi
cmp --silent "$WorkDir/$AppName/$AppExecCur.BCK" "$WorkDir/$AppName/$AppExecCur"
if [ "$?" != "0" ]; then
echo "${Meter59}patched something"
Patched="$Patched patched"
if [ $PCMkeepunpatched != "YES" ]; then
rm "$WorkDir/$AppName/$AppExecCur.BCK"
fi
else
echo "${Meter59}found nothing"
rm "$WorkDir/$AppName/$AppExecCur.BCK"
fi
fi
第八步:签名IWantYourSix
foo=$(ldid -s "$WorkDir/$AppName/$AppExecCur" 2>&1> /dev/null
第九步:armv7部分SevenTrumpets的cryptID修改为0(同第四步)
第十步:使用gdb将解密部分导出(同第五步)
# Cracking genuine executable in AppPath
#注意:对于fat binary,arm 7的设备上是默认按arm 7运行,所以需要使用没有经过swap header处理的原始mach-o文件 foo=$(gdb -q -e "$AppPath/$AppName/$AppExec" -x $WorkDir/batch.gdb -batch > /dev/null 2>&1> /dev/null)第十一步:用第九步中的解密部分替换SevenTrumpets加密部分(同第六步)
第十二步:使用lamerpatcher处理(不是必须的步骤)(同第七步)
第十三步:签名SevenTrumpets(同第八步)
第十四步:合并IWantYourSix和SevenTrumpets
if [ $LipoFail ]; then
rm -f "$WorkDir/$AppName/$AppExec"
echo "${Meter61}---"
if [ -e "$WorkDir/$AppName/SevenTrumpets" ]; then
echo "${Meter62}Combining both parts into a fat binary"
lipo -create "$WorkDir/$AppName/IWantYourSix" "$WorkDir/$AppName/SevenTrumpets" -output "$WorkDir/$AppName/$AppExec"
chmod 777 "$WorkDir/$AppName/$AppExec"
if [ $PCMkeepunpatched != "YES" ]; then
rm "$WorkDir/$AppName/IWantYourSix"
rm "$WorkDir/$AppName/SevenTrumpets"
fi
else
mv "$WorkDir/$AppName/IWantYourSix" "$WorkDir/$AppName/$AppExec"
chmod 777 "$WorkDir/$AppName/$AppExec"
fi
fi
第十五步:伪造可执行文件的时间戳,以应付破解检测(不是必须的步骤)
touch -r "$AppPath/$AppName/$AppExec" "$WorkDir/$AppName/$AppExec"
第十六步:根据MinOS版本(plutil -key MinimumOSVersion "Info.plist"),伪造SignerIdentity,目前主流是3.0版本,不需要伪造(不是必须的步骤)
echo -n "${Meter63}MinOS is '$MinOS': "
if [ ${MinOS:0:1} -gt 2 ]; then
echo "${Meter64}no SignerIdentity needed"
else
if [ $PCMsigner = "YES" ]; then
echo "${Meter64}adding SignerIdentity"
cp -a "$WorkDir/$AppName/Info.plist" "$WorkDir/$AppName/Info.backup.plist"
plutil -key 'SignerIdentity' -value 'Apple iPhone OS Application Signing' "$WorkDir/$AppName/Info.plist" 2>&1> /dev/null
plutil -binary "$WorkDir/$AppName/Info.plist" 2>&1> /dev/null
# Timestamp-back Info.plist to defeat checks
touch -r "$AppPath/$AppName/Info.plist" "$WorkDir/$AppName/Info.plist"
else
echo "${Meter64}but no SignerIdentity !"
fi
fi
第十七步:伪造iTunesMetadata.plist(不是必须的步骤)
cp "$AppPath/iTunesMetadata.plist" "$WorkDir/iTunesMetadataSource.plist"
plutil -xml "$WorkDir/iTunesMetadataSource.plist" 2>&1> /dev/null
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > "$WorkDir/iTunesMetadata.plist"
echo "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"https://www.apple.com/DTDs/PropertyList-1.0.dtd\">" >> "$WorkDir/iTunesMetadata.plist"
echo "<plist version=\"1.0\">" >> "$WorkDir/iTunesMetadata.plist"
echo "<dict>" >> "$WorkDir/iTunesMetadata.plist"
echo -e "\t<key>appleId</key>" >> "$WorkDir/iTunesMetadata.plist"
echo -e "\t<string>ChatMauve@apple.com</string>" >> "$WorkDir/iTunesMetadata.plist"
echo -e "\t<key>purchaseDate</key>" >> "$WorkDir/iTunesMetadata.plist"
echo -e "\t<date>2010-08-08T08:08:08Z</date>" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>artistId</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>artistName</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>buy-only</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>buyParams</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>copyright</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>drmVersionNumber</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>fileExtension</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 -m1 "<key>genre</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 -m1 "<key>genreId</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>itemId</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>itemName</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>kind</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>playlistArtistName</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>playlistName</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>price</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>priceDisplay</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A99 "<key>rating</key>" "$WorkDir/iTunesMetadataSource.plist" | grep -m1 -B99 "</dict>" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>releaseDate</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>s</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>softwareIcon57x57URL</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>softwareIconNeedsShine</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A99 "<key>softwareSupportedDeviceIds</key>" "$WorkDir/iTunesMetadataSource.plist" | grep -m1 -B99 "</array>" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>softwareVersionBundleId</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>softwareVersionExternalIdentifier</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A99 "<key>softwareVersionExternalIdentifiers</key>" "$WorkDir/iTunesMetadataSource.plist" | grep -m1 -B99 "</array>" >> "$WorkDir/iTunesMetadata.plist"
grep -A99 "<key>subgenres</key>" "$WorkDir/iTunesMetadataSource.plist" | grep -m1 -B99 "</array>" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>vendorId</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
grep -A1 "<key>versionRestrictions</key>" "$WorkDir/iTunesMetadataSource.plist" >> "$WorkDir/iTunesMetadata.plist"
echo "</dict>" >> "$WorkDir/iTunesMetadata.plist"
echo -e "</plist>\n" >> "$WorkDir/iTunesMetadata.plist"
# Timestamp Metadata to protect cracker
touch -r "$AppPath/$AppName/Info.plist" "$WorkDir/iTunesMetadata.plist"
第十八步:打包成ipa安装包
zip -y -r "$IPAName" Payload/* -x Payload/iTunesArtwork Payload/iTunesMetadata.plist "Payload/Documents/*" "Payload/Library/*" "Payload/tmp/*" "Payload/$AppName/$AppExec" "Payload/$AppName/Info.plist" "Payload/$AppName/SC_Info/*" "Payload/$AppName/_CodeSignature/*" "Payload/$AppName/CodeResources" "Payload/$AppName/ResourceRules.plist" 2>&1> /dev/null
整个过程,除去前期检测必要工具是否存在(例如ldid,plutil,otool),伪造特征文件,可以总结为以下几步:
第一步. 将fat binary切分为armv6,armv7部分(采用swap header技巧)第二步:获得cryptid,cryptsize,cryptsize
第三步. 将armv6部分的cryptid修改为0,gdb导出对应的armv6解密部分(对经过swap header处理的Mach-O文件进行操作,使得在arm 7设备上,强制运行arm 6部分),替换掉armv6加密部分,签名
第四步. 将armv7部分的cryptid修改为0,gdb导出对应的armv7解密部分(对原Mach-O文件进行操作),替换掉armv7加密部分,签名
第五步.合并解密过的armv6,armv7
第六步.打包成ipa安装包
注明:第三步和第四步是破解的关键,破解是否成功的关键在于导出的解密部分是否正确完整。
由于binary fat格式的mach-o文件在arm 7设备上默认运行arm 7对应代码,当需要导出arm 6对应的解密部分时,要先经过swap header处理,使其在arm 7 设备上按arm 6运行。
来源:碳基体
评论