1 /**
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "object.h"
17
18 #include "utils/logger.h"
19
20 #include "configs/guard_context.h"
21 #include "program.h"
22 #include "util/assert_util.h"
23 #include "util/string_util.h"
24
25 namespace {
26 constexpr std::string_view TAG = "[Object]";
27 constexpr size_t LITERAL_OBJECT_ITEM_LEN = 2;
28 constexpr size_t LITERAL_OBJECT_COMMON_ITEM_GROUP_LEN = 4; // Every 4 elements represent a set of regular key values
29 constexpr size_t LITERAL_OBJECT_METHOD_ITEM_GROUP_LEN = 6; // Every 6 elements represent a set of regular key values
30 constexpr size_t MAX_EXPORT_ITEM_LEN = 10000;
31 } // namespace
32
ExtractNames(std::set<std::string> & strings) const33 void panda::guard::ObjectProperty::ExtractNames(std::set<std::string> &strings) const
34 {
35 strings.emplace(this->name_);
36 }
37
Build()38 void panda::guard::ObjectProperty::Build()
39 {
40 if (this->method_ == nullptr) {
41 return;
42 }
43
44 this->method_->nameNeedUpdate_ = this->needUpdate;
45 this->method_->Init();
46 this->method_->Create();
47 }
48
Update()49 void panda::guard::ObjectProperty::Update()
50 {
51 auto &literalArrayTable = this->program_->prog_->literalarray_table;
52 PANDA_GUARD_ASSERT_PRINT(literalArrayTable.find(this->literalArrayIdx_) == literalArrayTable.end(), TAG,
53 ErrorCode::GENERIC_ERROR, "get bad literalArrayIdx:" << this->literalArrayIdx_);
54
55 auto &literalArray = literalArrayTable.at(this->literalArrayIdx_);
56 if (this->contentNeedUpdate_) {
57 this->obfName_ = GuardContext::GetInstance()->GetNameMapping()->GetName(this->name_);
58 LOG(INFO, PANDAGUARD) << TAG << "obfName:" << this->obfName_;
59 literalArray.literals_[this->index_].value_ = this->obfName_;
60 }
61
62 if (this->method_) {
63 this->method_->Obfuscate();
64 literalArray.literals_[this->index_ + LITERAL_OBJECT_ITEM_LEN].value_ = this->method_->obfIdx_;
65 }
66 }
67
SetContentNeedUpdate(bool toUpdate)68 void panda::guard::ObjectProperty::SetContentNeedUpdate(bool toUpdate)
69 {
70 this->contentNeedUpdate_ = toUpdate && this->needUpdate;
71 this->needUpdate = true;
72
73 if (this->method_) {
74 this->method_->SetContentNeedUpdate(toUpdate);
75 }
76 }
77
Build()78 void panda::guard::Object::Build()
79 {
80 LOG(INFO, PANDAGUARD) << TAG << "object create for " << this->literalArrayIdx_ << " start";
81
82 const auto &parentFunc = this->program_->prog_->function_table.at(this->defineInsList_[0].function_->idx_);
83 const size_t nextInsIndex = this->defineInsList_[0].index_ + 1;
84 PANDA_GUARD_ASSERT_PRINT(nextInsIndex >= parentFunc.ins.size(), TAG, ErrorCode::GENERIC_ERROR,
85 "try to find next ins of createobjectwithbuffer get bad ins index:" << nextInsIndex);
86
87 const auto &ins = parentFunc.ins[nextInsIndex];
88 // The next instruction is stmodulevar, which exports the object
89 this->export_ = ins.opcode == pandasm::Opcode::STMODULEVAR;
90
91 LOG(INFO, PANDAGUARD) << TAG << "export:" << (this->export_ ? "true" : "false");
92 if (this->export_) {
93 int64_t index = std::get<int64_t>(ins.imms[0]);
94 PANDA_GUARD_ASSERT_PRINT(index < 0 || index > MAX_EXPORT_ITEM_LEN, TAG, ErrorCode::GENERIC_ERROR,
95 "unexpect export item index:" << index);
96 this->name_ = this->moduleRecord->GetLocalExportName(index);
97 this->obfName_ = this->name_;
98 this->SetNameCacheScope(this->name_);
99 LOG(INFO, PANDAGUARD) << TAG << "name:" << this->name_;
100 }
101
102 const auto &literalArray = this->program_->prog_->literalarray_table.at(this->literalArrayIdx_);
103 size_t keyIndex = 1; // object item key index
104 size_t valueIndex = keyIndex + LITERAL_OBJECT_ITEM_LEN; // object item value index
105 while (valueIndex < literalArray.literals_.size()) {
106 auto &valueLiteral = literalArray.literals_[valueIndex];
107 bool isMethod = valueLiteral.tag_ == panda_file::LiteralTag::METHOD;
108 CreateProperty(literalArray, keyIndex, isMethod);
109 if (isMethod) {
110 keyIndex += LITERAL_OBJECT_METHOD_ITEM_GROUP_LEN;
111 } else {
112 keyIndex += LITERAL_OBJECT_COMMON_ITEM_GROUP_LEN;
113 }
114 valueIndex = keyIndex + LITERAL_OBJECT_ITEM_LEN;
115 }
116 LOG(INFO, PANDAGUARD) << TAG << "object create for " << this->literalArrayIdx_ << " end";
117 }
118
CreateProperty(const pandasm::LiteralArray & literalArray,size_t index,bool isMethod)119 void panda::guard::Object::CreateProperty(const pandasm::LiteralArray &literalArray, size_t index, bool isMethod)
120 {
121 const auto &[keyTag, keyValue] = literalArray.literals_[index];
122 PANDA_GUARD_ASSERT_PRINT(keyTag != panda_file::LiteralTag::STRING, TAG, ErrorCode::GENERIC_ERROR,
123 "bad keyTag literal tag");
124
125 ObjectProperty property(this->program_, this->literalArrayIdx_);
126 property.name_ = StringUtil::UnicodeEscape(std::get<std::string>(keyValue));
127 property.scope_ = this->scope_;
128 property.export_ = this->export_;
129 property.index_ = index;
130
131 if (isMethod) {
132 size_t valueLiteralIndex = index + 2;
133 PANDA_GUARD_ASSERT_PRINT(valueLiteralIndex >= literalArray.literals_.size(), TAG, ErrorCode::GENERIC_ERROR,
134 "bad valueLiteralIndex:" << valueLiteralIndex);
135 const auto &[valueTag, valueValue] = literalArray.literals_[valueLiteralIndex];
136 PANDA_GUARD_ASSERT_PRINT(valueTag != panda_file::LiteralTag::METHOD, TAG, ErrorCode::GENERIC_ERROR,
137 "bad valueLiteral tag:" << (int)valueTag);
138 property.method_ = std::make_shared<PropertyMethod>(this->program_, std::get<std::string>(valueValue));
139 property.method_->export_ = this->export_;
140 property.method_->scope_ = this->scope_;
141 }
142
143 property.Create();
144
145 LOG(INFO, PANDAGUARD) << TAG << "find object property:" << property.name_;
146
147 this->properties_.push_back(property);
148 }
149
ForEachMethod(const std::function<FunctionTraver> & callback)150 void panda::guard::Object::ForEachMethod(const std::function<FunctionTraver> &callback)
151 {
152 for (const auto &property : this->properties_) {
153 if (property.method_) {
154 callback(property.method_.operator*());
155 }
156 }
157
158 for (auto &method : this->outerMethods_) {
159 callback(method);
160 }
161 }
162
ExtractNames(std::set<std::string> & strings) const163 void panda::guard::Object::ExtractNames(std::set<std::string> &strings) const
164 {
165 for (const auto &property : this->properties_) {
166 property.ExtractNames(strings);
167 }
168 }
169
RefreshNeedUpdate()170 void panda::guard::Object::RefreshNeedUpdate()
171 {
172 this->needUpdate = true;
173 this->needUpdateName_ = TopLevelOptionEntity::NeedUpdate(*this);
174 }
175
Update()176 void panda::guard::Object::Update()
177 {
178 LOG(INFO, PANDAGUARD) << TAG << "object update for " << this->literalArrayIdx_ << " start";
179
180 if (this->contentNeedUpdate_ && this->needUpdateName_ && !this->name_.empty()) {
181 this->obfName_ = GuardContext::GetInstance()->GetNameMapping()->GetName(this->name_);
182 }
183
184 for (auto &property : this->properties_) {
185 property.Obfuscate();
186 }
187
188 for (auto &property : this->outerProperties_) {
189 property.Obfuscate();
190 }
191
192 for (auto &method : this->outerMethods_) {
193 method.Obfuscate();
194 }
195
196 LOG(INFO, PANDAGUARD) << TAG << "object update for " << this->literalArrayIdx_ << " end";
197 }
198
WriteNameCache(const std::string & filePath)199 void panda::guard::Object::WriteNameCache(const std::string &filePath)
200 {
201 if (!this->obfuscated || !this->contentNeedUpdate_) {
202 return;
203 }
204
205 if (this->needUpdateName_ && !this->obfName_.empty()) {
206 GuardContext::GetInstance()->GetNameCache()->AddObfIdentifierName(filePath, this->GetNameCacheScope(),
207 this->obfName_);
208 }
209
210 for (auto &property : this->properties_) {
211 property.WriteNameCache(filePath);
212 }
213
214 for (auto &property : this->outerProperties_) {
215 property.WriteNameCache(filePath);
216 }
217 }
218
SetContentNeedUpdate(bool toUpdate)219 void panda::guard::Object::SetContentNeedUpdate(bool toUpdate)
220 {
221 this->contentNeedUpdate_ = toUpdate;
222 for (auto &property : this->properties_) {
223 property.SetContentNeedUpdate(toUpdate);
224 }
225 for (auto &method : this->outerMethods_) {
226 method.SetContentNeedUpdate(toUpdate);
227 }
228 }
229