自笔者开始学习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"\"";
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!
最后于 2024-1-18 22:07
被简单的简单编辑
,原因: