自笔者开始学习Android逆向的第一天起就一直被一个问题所困扰,那就是 AndroidManifest 的编码总是会有问题,相信大家在使用 apktool 的时候如果直接 java -jar apktool.jar d HelloWorld.apk
那么在回编译的时候大概率会出现报错,这是因为 apktool 的资源的解析是有问题的,添加参数 -r 可以屏蔽资源的解析,但这样一来 AndroidManifest 就无法解析,而在逆向的过程中很常见的需求就是修改 AndroidManifest,例如修改启动类又或者添加debug标志,所以很容易想到的方法就是 apktool.jar 屏蔽资源解析,然后使用针对 AndroidManifest 修改的工具,这其中有许多大佬开源了自己的 AndroidManifest 修改工具,但在笔者的使用过程中总是会有这样那样的问题,正好最近有个需求是修改 AndroidManifest,所以在这里记录下 AndroidManifest.xml 二进制文件格式分析。
首先按照惯例先贴上这张神图,可以说总结的非常全面,但此图也有自己的问题,那就是难以让读者在心中对整个 AndroidManifest 格式有一个大概的雏形。
在这张图中我们需要明白整个 AndroidManifest 格式分为六大区域,七种 Chunk 类型,依次分别为 AndroidManifestHead、StringChunk、ResourceChunk、StartNamespaceChunk、StartTagChunk&EndTagChunk、EndNameSpaceChunk,其中多数情况 ResourceChunk为空,不太需要处理。
AndroidManifestHead 占据 AndroidManifest 的起始8个字节,magic 标志着这个文件是 AndroidManifest 格式,file_size 记录 AndroidManifest.xml 文件的大小,这种文件头可以说是异常简单了。
笔者在分析完 AndroidManifest 后总结出 StringChunk、ResourceChunk、StartNamespaceChunk、StartTagChunk、EndTagChunk、EndNameSpaceChunk 这六种块的前 8 个字节是一样的
由此我们可以先对 AndroidManifest 进行一个大致的遍历
输出的结果大致为这样,可以完美对应上方的结构图
StringChunk 的格式就略显复杂了,首先我们先看下 StringChunk 的头部,这部分共计 7 * 4 = 28 个字节的大小
StringChunk 的头部后面跟着的就是 StringOffsets,这部分区域是的大小为 scStringCount *4,其中每4个字节记录了对应 StringItem 在文件中的的偏移,这里画了一个图可以直观理解一下。
根据上述的分析,故此我们可以定义如下两个类 StringItem、StringChunk
StartNamespaceChunk 中主要的字段为 sncPrefix,可以轻易解析通过 StringChunk 解析
和 StartNamespaceChunk 不能说一模一样,只能说完全相同
StartTagChunk 也是稍显复杂的一个结构,因为其中包含了另一个结构 AttributeChunk,这里同样给出一个关系结构图
由此我们可以定义如下两个类 AttributeChunk、StartTagChunk
EndTagChunk 的结构就没 StartTagChunk 那么复杂了,可以说简单的很
自此我们在为借助其他第三方模块的完成了绝大部分 Chunk 的解析,AndroidManifest 也变得不再神秘,那么就简单的 show 一下吧
现在 AndroidManifest 已经可以任由我们搓扁揉圆了,重新组装 StringChunk 一下,就可以向其中添加任意的字符串
当 AndroidManifest 中已存在 ApplicationName 时直接修改其字符串偏移即可
AndroidManifest 的数据结构总体来讲不算过于复杂,和PE/ELF比算是小巫见大巫了,不过由于搞得不是很精细,后续还需要多做一些测试
Android逆向之旅—解析编译之后的AndroidManifest文件格式
AndroidManifest二进制文件格式分析
Android逆向笔记 —— AndroidManifest.xml 文件格式解析
struct sAndroidManifestHead {
int
magic;
/
/
标志着这个文件是 AndroidManifest 格式
int
file_size;
/
/
记录 AndroidManifest.xml 文件的大小
};
struct sAndroidManifestHead {
int
magic;
/
/
标志着这个文件是 AndroidManifest 格式
int
file_size;
/
/
记录 AndroidManifest.xml 文件的大小
};
class
Chunk {
public
:
struct
sChunk {
int
cSignature;
int
cSize;
};
char
* addr;
int
cSignature;
int
cSize;
std::string type;
Chunk(
char
* chunk_addr) {
addr = chunk_addr;
sChunk* mChunk = (sChunk*)chunk_addr;
if
(mChunk->cSignature == 0x001c0001) {
type =
"StringChunk"
;
}
else
if
(mChunk->cSignature == 0x00080180) {
type =
"ResourceChunk"
;
}
else
if
(mChunk->cSignature == 0x00100100) {
type =
"StartNameSpaceChunk"
;
}
else
if
(mChunk->cSignature == 0x00100102) {
type =
"StartTagChunk"
;
}
else
if
(mChunk->cSignature == 0x00100103) {
type =
"EndTagChunk"
;
}
else
if
(mChunk->cSignature == 0x00100101) {
type =
"EndNameSpaceChunk"
;
}
else
{
type =
"Unknown"
;
}
cSize = mChunk->cSize;
};
Chunk* NextChunk() {
return
new
Chunk((addr + cSize));
}
};
class
Chunk {
public
:
struct
sChunk {
int
cSignature;
int
cSize;
};
char
* addr;
int
cSignature;
int
cSize;
std::string type;
Chunk(
char
* chunk_addr) {
addr = chunk_addr;
sChunk* mChunk = (sChunk*)chunk_addr;
if
(mChunk->cSignature == 0x001c0001) {
type =
"StringChunk"
;
}
else
if
(mChunk->cSignature == 0x00080180) {
type =
"ResourceChunk"
;
}
else
if
(mChunk->cSignature == 0x00100100) {
type =
"StartNameSpaceChunk"
;
}
else
if
(mChunk->cSignature == 0x00100102) {
type =
"StartTagChunk"
;
}
else
if
(mChunk->cSignature == 0x00100103) {
type =
"EndTagChunk"
;
}
else
if
(mChunk->cSignature == 0x00100101) {
type =
"EndNameSpaceChunk"
;
}
else
{
type =
"Unknown"
;
}
cSize = mChunk->cSize;
};
Chunk* NextChunk() {
return
new
Chunk((addr + cSize));
}
};
int
main() {
const
char
* AndroidManifestPath =
"C:\\Users\\lxz\\source\\repos\\AndroidManifestEditor\\AndroidManifest.xml"
;
char
* mAndroidManifestData = read_file(AndroidManifestPath);
sAndroidManifestHead* mAndroidManifestHead = (sAndroidManifestHead*)mAndroidManifestData;
std::vector<Chunk*> chunkList;
Chunk* chunk =
new
Chunk(((
char
*)mAndroidManifestHead +
sizeof
(sAndroidManifestHead)));
while
(chunk->type !=
"Unknown"
) {
chunkList.push_back(chunk);
chunk = chunk->NextChunk();
}
for
(Chunk* chunk : chunkList) {
printf
(
"%s\n\n"
, chunk->type.c_str());
delete
chunk;
}
chunkList.clear();
}
int
main() {
const
char
* AndroidManifestPath =
"C:\\Users\\lxz\\source\\repos\\AndroidManifestEditor\\AndroidManifest.xml"
;
char
* mAndroidManifestData = read_file(AndroidManifestPath);
sAndroidManifestHead* mAndroidManifestHead = (sAndroidManifestHead*)mAndroidManifestData;
std::vector<Chunk*> chunkList;
Chunk* chunk =
new
Chunk(((
char
*)mAndroidManifestHead +
sizeof
(sAndroidManifestHead)));
while
(chunk->type !=
"Unknown"
) {
chunkList.push_back(chunk);
chunk = chunk->NextChunk();
}
for
(Chunk* chunk : chunkList) {
printf
(
"%s\n\n"
, chunk->type.c_str());
delete
chunk;
}
chunkList.clear();
}
stringChunk
resourceChunk
startNameSpaceChunk
startTagChunk
startTagChunk
endTagChunk
startTagChunk
......
endTagChunk
endTagChunk
EndNameSpaceChunk
stringChunk
resourceChunk
startNameSpaceChunk
startTagChunk
startTagChunk
endTagChunk
startTagChunk
......
endTagChunk
endTagChunk
EndNameSpaceChunk
struct sStringChunk {
int
scSignature;
/
/
块类型标识
int
scSize;
/
/
块大小
int
scStringCount;
/
/
字符串数量
int
scStyleCount;
/
/
未知
int
scUNKNOWN;
/
/
未知
int
scStringPoolOffset;
/
/
字符串集合的偏移
int
scStylePoolOffset;
/
/
未知
};
struct sStringChunk {
int
scSignature;
/
/
块类型标识
int
scSize;
/
/
块大小
int
scStringCount;
/
/
字符串数量
int
scStyleCount;
/
/
未知
int
scUNKNOWN;
/
/
未知
int
scStringPoolOffset;
/
/
字符串集合的偏移
int
scStylePoolOffset;
/
/
未知
};
class
StringItem {
public
:
std::wstring wstr;
char
* raw;
int
size;
StringItem(
char
* addr) {
size = 2 + (*(
wchar_t
*)addr) * 2 + 2;
wstr = std::wstring((
wchar_t
*)(addr + 2));
raw = addr;
}
StringItem(std::wstring v_wstr) {
wstr = v_wstr;
size = 2 + wstr.length() * 2 + 2;
raw = (
char
*)
malloc
(size);
memset
(raw, 0, size);
*(
int
*)raw = wstr.length();
memcpy
(raw + 2, wstr.c_str(), wstr.length() * 2);
}
};
class
StringChunk {
public
:
struct
sStringChunk {
int
scSignature;
int
scSize;
int
scStringCount;
int
scStyleCount;
int
scUNKNOWN;
int
scStringPoolOffset;
int
scStylePoolOffset;
};
char
* addr;
int
scSignature;
int
scSize;
int
scStringCount;
int
scStyleCount;
int
scUNKNOWN;
int
scStringPoolOffset;
int
scStylePoolOffset;
int
* scStringOffsets;
std::vector<
int
> StringOffset_list;
std::vector<StringItem*> StringItem_list;
StringChunk(
char
* chunk_addr) {
addr = chunk_addr;
scSignature = ((sStringChunk*)chunk_addr)->scSignature;
scSize = ((sStringChunk*)chunk_addr)->scSize;
scStringCount = ((sStringChunk*)chunk_addr)->scStringCount;
scStyleCount = ((sStringChunk*)chunk_addr)->scStyleCount;
scUNKNOWN = ((sStringChunk*)chunk_addr)->scUNKNOWN;
scStringPoolOffset = ((sStringChunk*)chunk_addr)->scStringPoolOffset;
scStylePoolOffset = ((sStringChunk*)chunk_addr)->scStylePoolOffset;
scStringOffsets = (
int
*)(chunk_addr +
sizeof
(sStringChunk));
for
(
int
i = 0; i < scStringCount; i++) {
StringOffset_list.push_back(*(scStringOffsets + i));
StringItem_list.push_back(
new
StringItem(addr + scStringPoolOffset + *(scStringOffsets + i)));
}
};
std::wstring get_string(
int
id) {
return
(
wchar_t
*)(addr + scStringPoolOffset + *(scStringOffsets + id) + 2);
}
void
show_all_string() {
for
(
int
i = 0; i < scStringCount; i++) {
printf
(
"%S \n"
, get_string(i).c_str());
}
}
};
class
StringItem {
public
:
std::wstring wstr;
char
* raw;
int
size;
StringItem(
char
* addr) {
size = 2 + (*(
wchar_t
*)addr) * 2 + 2;
wstr = std::wstring((
wchar_t
*)(addr + 2));
raw = addr;
}
StringItem(std::wstring v_wstr) {
wstr = v_wstr;
size = 2 + wstr.length() * 2 + 2;
raw = (
char
*)
malloc
(size);
memset
(raw, 0, size);
*(
int
*)raw = wstr.length();
memcpy
(raw + 2, wstr.c_str(), wstr.length() * 2);
}
};
class
StringChunk {
public
:
struct
sStringChunk {
int
scSignature;
int
scSize;
int
scStringCount;
int
scStyleCount;
int
scUNKNOWN;
int
scStringPoolOffset;
int
scStylePoolOffset;
};
char
* addr;
int
scSignature;
int
scSize;
int
scStringCount;
int
scStyleCount;
int
scUNKNOWN;
int
scStringPoolOffset;
int
scStylePoolOffset;
int
* scStringOffsets;
std::vector<
int
> StringOffset_list;
std::vector<StringItem*> StringItem_list;
StringChunk(
char
* chunk_addr) {
addr = chunk_addr;
scSignature = ((sStringChunk*)chunk_addr)->scSignature;
scSize = ((sStringChunk*)chunk_addr)->scSize;
scStringCount = ((sStringChunk*)chunk_addr)->scStringCount;
scStyleCount = ((sStringChunk*)chunk_addr)->scStyleCount;
scUNKNOWN = ((sStringChunk*)chunk_addr)->scUNKNOWN;
scStringPoolOffset = ((sStringChunk*)chunk_addr)->scStringPoolOffset;
scStylePoolOffset = ((sStringChunk*)chunk_addr)->scStylePoolOffset;
scStringOffsets = (
int
*)(chunk_addr +
sizeof
(sStringChunk));
for
(
int
i = 0; i < scStringCount; i++) {
StringOffset_list.push_back(*(scStringOffsets + i));
StringItem_list.push_back(
new
StringItem(addr + scStringPoolOffset + *(scStringOffsets + i)));
}
};
std::wstring get_string(
int
id) {
return
(
wchar_t
*)(addr + scStringPoolOffset + *(scStringOffsets + id) + 2);
}
void
show_all_string() {
for
(
int
i = 0; i < scStringCount; i++) {
printf
(
"%S \n"
, get_string(i).c_str());
}
}
};
class
StartNamespaceChunk {
public
:
struct
sStartNamespaceChunk {
int
scSignature;
int
scSize;
int
sncLineNumber;
int
sncUNKNOWN;
int
sncPrefix;
int
sncUri;
};
char
* addr;
int
scSignature;
int
scSize;
int
sncLineNumber;
int
sncUNKNOWN;
int
sncPrefix;
int
sncUri;
StringChunk*& mStringChunk;
StartNamespaceChunk(
char
* chunk_addr, StringChunk** vStringChunk):mStringChunk(*vStringChunk) {
addr = chunk_addr;
scSignature = ((sStartNamespaceChunk*)addr)->scSignature;
scSize = ((sStartNamespaceChunk*)addr)->scSize;
sncLineNumber = ((sStartNamespaceChunk*)addr)->sncLineNumber;
sncUNKNOWN = ((sStartNamespaceChunk*)addr)->sncUNKNOWN;
sncPrefix = ((sStartNamespaceChunk*)addr)->sncPrefix;
sncUri = ((sStartNamespaceChunk*)addr)->sncUri;
};
std::wstring get_string() {
return
mStringChunk->get_string(sncPrefix);
}
};
class
StartNamespaceChunk {
public
:
struct
sStartNamespaceChunk {
int
scSignature;
int
scSize;
int
sncLineNumber;
int
sncUNKNOWN;
int
sncPrefix;
int
sncUri;
};
char
* addr;
int
scSignature;
int
scSize;
int
sncLineNumber;
int
sncUNKNOWN;
int
sncPrefix;
int
sncUri;
StringChunk*& mStringChunk;
StartNamespaceChunk(
char
* chunk_addr, StringChunk** vStringChunk):mStringChunk(*vStringChunk) {
addr = chunk_addr;
scSignature = ((sStartNamespaceChunk*)addr)->scSignature;
scSize = ((sStartNamespaceChunk*)addr)->scSize;
sncLineNumber = ((sStartNamespaceChunk*)addr)->sncLineNumber;
sncUNKNOWN = ((sStartNamespaceChunk*)addr)->sncUNKNOWN;
sncPrefix = ((sStartNamespaceChunk*)addr)->sncPrefix;
sncUri = ((sStartNamespaceChunk*)addr)->sncUri;
};
std::wstring get_string() {
return
mStringChunk->get_string(sncPrefix);
}
};
class
EndNameSpaceChunk {
public
:
struct
sEndTagChunk {
int
encSignature;
int
encSize;
int
encLineNumber;
int
encUNKNOWN;
int
encPrefix;
int
encUri;
};
char
* addr;
int
encSignature;
int
encSize;
int
encLineNumber;
int
encUNKNOWN;
int
encPrefix;
int
encUri;
StringChunk*& mStringChunk;
EndNameSpaceChunk(
char
* chunk_addr, StringChunk** vStringChunk): mStringChunk(*vStringChunk) {
addr = chunk_addr;
encSignature = ((sEndTagChunk*)addr)->encSignature;
encSize = ((sEndTagChunk*)addr)->encSize;
encLineNumber = ((sEndTagChunk*)addr)->encLineNumber;
encUNKNOWN = ((sEndTagChunk*)addr)->encUNKNOWN;
encPrefix = ((sEndTagChunk*)addr)->encPrefix;
encUri = ((sEndTagChunk*)addr)->encUri;
};
std::wstring get_string() {
return
mStringChunk->get_string(encPrefix);
}
};
class
EndNameSpaceChunk {
public
:
struct
sEndTagChunk {
int
encSignature;
int
encSize;
int
encLineNumber;
int
encUNKNOWN;
int
encPrefix;
int
encUri;
};
char
* addr;
int
encSignature;
int
encSize;
int
encLineNumber;
int
encUNKNOWN;
int
encPrefix;
int
encUri;
StringChunk*& mStringChunk;
EndNameSpaceChunk(
char
* chunk_addr, StringChunk** vStringChunk): mStringChunk(*vStringChunk) {
addr = chunk_addr;
encSignature = ((sEndTagChunk*)addr)->encSignature;
encSize = ((sEndTagChunk*)addr)->encSize;
encLineNumber = ((sEndTagChunk*)addr)->encLineNumber;
encUNKNOWN = ((sEndTagChunk*)addr)->encUNKNOWN;
encPrefix = ((sEndTagChunk*)addr)->encPrefix;
encUri = ((sEndTagChunk*)addr)->encUri;
};
std::wstring get_string() {
return
mStringChunk->get_string(encPrefix);
}
};
class
AttributeChunk {
public
:
struct
sAttributeChunk {
int
acNamespaceUri;
int
acName;
int
acValueStr;
int
acType;
int
acData;
};
int
acNamespaceUri;
int
acName;
int
acValueStr;
int
acType;
int
acData;
char
* addr;
StringChunk*& mStringChunk;
StartNamespaceChunk*& mStartNamespaceChunk;
AttributeChunk(
char
* chunk_addr, StringChunk** vStringChunk, StartNamespaceChunk** vStartNamespaceChunk):mStringChunk(*vStringChunk), mStartNamespaceChunk(*vStartNamespaceChunk) {
addr = chunk_addr;
acNamespaceUri = ((sAttributeChunk*)addr)->acNamespaceUri;
acName = ((sAttributeChunk*)addr)->acName;
acValueStr = ((sAttributeChunk*)addr)->acValueStr;
acType = ((sAttributeChunk*)addr)->acType;
acData = ((sAttributeChunk*)addr)->acData;
}
std::wstring get_srting() {
std::wstring resData = L
""
;
if
(acNamespaceUri != -1 && acNamespaceUri == mStartNamespaceChunk->sncUri) {
resData = mStartNamespaceChunk->get_string() + L
":"
;
}
resData += mStringChunk->get_string(acName);
resData += L
"="
;
if
((acType >> 24) == 0x10) {
resData += L
"\""
;
resData += std::to_wstring(acData);
resData += L
"\""
;
}
else
if
((acType >> 24) == 0x3) {
resData += L
"\""
;
resData += mStringChunk->get_string(acValueStr);
resData += L
"\""
;
}
else
if
((acType >> 24) == 0x12) {
if
(acData == -1) {
resData += L
"\"true\""
;
}
else
if
(acData == 0) {
resData += L
"\"false\""
;
}
}
else
if
((acType >> 24) == 0x1) {
std::wstringstream wss;
wss << std::hex << acData;
std::wstring hexString = wss.str();
resData += L
"\"@"
;
resData += std::wstring(wss.str());
resData += L
"\""
;
}
else
{
std::wstringstream wss;
wss << std::hex << acData;
std::wstring hexString = wss.str();
resData += L
"\"[Error]"
;
resData += std::wstring(wss.str());
resData += L
"\""
;
}
return
resData;
}
void
change_value(
int
value) {
((sAttributeChunk*)addr)->acValueStr = value;
acValueStr = value;
}
};
class
StartTagChunk {
public
:
struct
sStartTagChunk {
int
stcSignature;
int
stcSize;
int
stcLineNumber;
int
stcUNKNOWN;
int
stcNamespaceUri;
int
stcName;
int
stcFlags;
int
stcAttributeCount;
int
stcClassAttribute;
};
char
* addr;
int
stcSignature;
int
stcSize;
int
stcLineNumber;
int
stcUNKNOWN;
int
stcNamespaceUri;
int
stcName;
int
stcFlags;
int
stcAttributeCount;
int
stcClassAttribute;
EndTagChunk* mEndTagChunk;
StringChunk*& mStringChunk;
StartNamespaceChunk*& mStartNamespaceChunk;
std::vector<AttributeChunk*> mAttributeChunkList;
StartTagChunk(
char
* chunk_addr, StringChunk** vStringChunk, StartNamespaceChunk** vStartNamespaceChunk)
: mStringChunk(*vStringChunk), mStartNamespaceChunk(*vStartNamespaceChunk){
addr = chunk_addr;
stcSignature = ((sStartTagChunk*)addr)->stcSignature;
stcSize = ((sStartTagChunk*)addr)->stcSize;
stcLineNumber = ((sStartTagChunk*)addr)->stcLineNumber;
stcUNKNOWN = ((sStartTagChunk*)addr)->stcUNKNOWN;
stcName = ((sStartTagChunk*)addr)->stcName;
stcFlags = ((sStartTagChunk*)addr)->stcFlags;
stcAttributeCount = ((sStartTagChunk*)addr)->stcAttributeCount;
stcClassAttribute = ((sStartTagChunk*)addr)->stcClassAttribute;
for
(
int
i = 0; i < stcAttributeCount; i++) {
AttributeChunk* mAttributeChunk =
new
AttributeChunk(addr +
sizeof
(sStartTagChunk) + 20 * i, &mStringChunk, &mStartNamespaceChunk);
mAttributeChunkList.push_back(mAttributeChunk);
}
};
std::wstring get_string() {
std::wstring resData = L
""
;
for
(
int
i = 0; i < mAttributeChunkList.size(); i++) {
resData += mAttributeChunkList[i]->get_srting();
resData += L
"\n"
;
}
return
resData;
}
};
class
AttributeChunk {
public
:
struct
sAttributeChunk {
int
acNamespaceUri;
int
acName;
int
acValueStr;
int
acType;
int
acData;
};
int
acNamespaceUri;
int
acName;
int
acValueStr;
int
acType;
int
acData;
char
* addr;
StringChunk*& mStringChunk;
StartNamespaceChunk*& mStartNamespaceChunk;
AttributeChunk(
char
* chunk_addr, StringChunk** vStringChunk, StartNamespaceChunk** vStartNamespaceChunk):mStringChunk(*vStringChunk), mStartNamespaceChunk(*vStartNamespaceChunk) {
addr = chunk_addr;
acNamespaceUri = ((sAttributeChunk*)addr)->acNamespaceUri;
acName = ((sAttributeChunk*)addr)->acName;
acValueStr = ((sAttributeChunk*)addr)->acValueStr;
acType = ((sAttributeChunk*)addr)->acType;
acData = ((sAttributeChunk*)addr)->acData;
}
std::wstring get_srting() {
std::wstring resData = L
""
;
if
(acNamespaceUri != -1 && acNamespaceUri == mStartNamespaceChunk->sncUri) {
resData = mStartNamespaceChunk->get_string() + L
":"
;
}
resData += mStringChunk->get_string(acName);
resData += L
"="
;
if
((acType >> 24) == 0x10) {
resData += L
"\""
;
resData += std::to_wstring(acData);
resData += L
"\""
;
}
else
if
((acType >> 24) == 0x3) {
resData += L
"\""
;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2024-1-18 22:07
被简单的简单编辑
,原因: