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 } // namespace
31
ExtractNames(std::set<std::string> & strings) const32 void panda::guard::ObjectProperty::ExtractNames(std::set<std::string> &strings) const
33 {
34 strings.emplace(this->name_);
35 }
36
Build()37 void panda::guard::ObjectProperty::Build()
38 {
39 if (this->method_ == nullptr) {
40 return;
41 }
42
43 this->method_->nameNeedUpdate_ = this->needUpdate_;
44 this->method_->Init();
45 this->method_->Create();
46 }
47
Update()48 void panda::guard::ObjectProperty::Update()
49 {
50 auto &literalArrayTable = this->program_->prog_->literalarray_table;
51 PANDA_GUARD_ASSERT_PRINT(literalArrayTable.find(this->literalArrayIdx_) == literalArrayTable.end(), TAG,
52 ErrorCode::GENERIC_ERROR, "get bad literalArrayIdx:" << this->literalArrayIdx_);
53
54 auto &literalArray = literalArrayTable.at(this->literalArrayIdx_);
55 if (this->contentNeedUpdate_) {
56 this->obfName_ = GuardContext::GetInstance()->GetNameMapping()->GetName(this->name_);
57 LOG(INFO, PANDAGUARD) << TAG << "obfName:" << this->obfName_;
58 literalArray.literals_[this->index_].value_ = this->obfName_;
59 }
60
61 if (this->method_) {
62 this->method_->Obfuscate();
63 literalArray.literals_[this->index_ + LITERAL_OBJECT_ITEM_LEN].value_ = this->method_->obfIdx_;
64 }
65 }
66
SetContentNeedUpdate(bool toUpdate)67 void panda::guard::ObjectProperty::SetContentNeedUpdate(bool toUpdate)
68 {
69 this->contentNeedUpdate_ = toUpdate && this->needUpdate_;
70 this->needUpdate_ = true;
71
72 if (this->method_) {
73 this->method_->SetContentNeedUpdate(toUpdate);
74 }
75 }
76
SetExportAndRefreshNeedUpdate(bool isExport)77 void panda::guard::ObjectProperty::SetExportAndRefreshNeedUpdate(bool isExport)
78 {
79 if (this->method_) {
80 this->method_->SetExportAndRefreshNeedUpdate(isExport);
81 }
82
83 Entity::SetExportAndRefreshNeedUpdate(isExport);
84 }
85
Build()86 void panda::guard::Object::Build()
87 {
88 LOG(INFO, PANDAGUARD) << TAG << "object create for " << this->literalArrayIdx_ << " start";
89
90 const auto &literalArray = this->program_->prog_->literalarray_table.at(this->literalArrayIdx_);
91 size_t keyIndex = 1; // object item key index
92 size_t valueIndex = keyIndex + LITERAL_OBJECT_ITEM_LEN; // object item value index
93 while (valueIndex < literalArray.literals_.size()) {
94 auto &valueLiteral = literalArray.literals_[valueIndex];
95 const bool isMethod = valueLiteral.tag_ == panda_file::LiteralTag::METHOD;
96 CreateProperty(literalArray, keyIndex, isMethod);
97 if (isMethod) {
98 keyIndex += LITERAL_OBJECT_METHOD_ITEM_GROUP_LEN;
99 } else {
100 keyIndex += LITERAL_OBJECT_COMMON_ITEM_GROUP_LEN;
101 }
102 valueIndex = keyIndex + LITERAL_OBJECT_ITEM_LEN;
103 }
104 LOG(INFO, PANDAGUARD) << TAG << "object create for " << this->literalArrayIdx_ << " end";
105 }
106
CreateProperty(const pandasm::LiteralArray & literalArray,size_t index,bool isMethod)107 void panda::guard::Object::CreateProperty(const pandasm::LiteralArray &literalArray, size_t index, bool isMethod)
108 {
109 const auto &[keyTag, keyValue] = literalArray.literals_[index];
110 PANDA_GUARD_ASSERT_PRINT(keyTag != panda_file::LiteralTag::STRING, TAG, ErrorCode::GENERIC_ERROR,
111 "bad keyTag literal tag");
112
113 const auto property = std::make_shared<ObjectProperty>(this->program_, this->literalArrayIdx_);
114 property->name_ = StringUtil::UnicodeEscape(std::get<std::string>(keyValue));
115 property->scope_ = this->scope_;
116 property->export_ = this->export_;
117 property->index_ = index;
118
119 if (isMethod) {
120 const size_t valueLiteralIndex = index + 2;
121 PANDA_GUARD_ASSERT_PRINT(valueLiteralIndex >= literalArray.literals_.size(), TAG, ErrorCode::GENERIC_ERROR,
122 "bad valueLiteralIndex:" << valueLiteralIndex);
123 const auto &[valueTag, valueValue] = literalArray.literals_[valueLiteralIndex];
124 PANDA_GUARD_ASSERT_PRINT(valueTag != panda_file::LiteralTag::METHOD, TAG, ErrorCode::GENERIC_ERROR,
125 "bad valueLiteral tag:" << (int)valueTag);
126 property->method_ = std::make_shared<PropertyMethod>(this->program_, std::get<std::string>(valueValue));
127 property->method_->node_ = this->node_;
128 property->method_->export_ = this->export_;
129 property->method_->scope_ = this->scope_;
130 }
131
132 property->Create();
133
134 LOG(INFO, PANDAGUARD) << TAG << "find object property:" << property->name_;
135
136 this->properties_.push_back(property);
137 }
138
UpdateLiteralArrayIdx()139 void panda::guard::Object::UpdateLiteralArrayIdx()
140 {
141 if (!GuardContext::GetInstance()->GetGuardOptions()->IsFileNameObfEnabled()) {
142 return;
143 }
144
145 const auto &it = this->program_->nodeTable_.find(this->recordName_);
146 PANDA_GUARD_ASSERT_PRINT(it == this->program_->nodeTable_.end(), TAG, ErrorCode::GENERIC_ERROR,
147 "not find node: " + this->recordName_);
148 const auto &node = it->second;
149 if (node->name_ == node->obfName_) {
150 return;
151 }
152 std::string updatedLiteralArrayIdx = this->literalArrayIdx_;
153 updatedLiteralArrayIdx.replace(updatedLiteralArrayIdx.find(node->name_), node->name_.size(), node->obfName_);
154
155 UpdateLiteralArrayTableIdx(this->literalArrayIdx_, updatedLiteralArrayIdx);
156
157 this->literalArrayIdx_ = updatedLiteralArrayIdx;
158
159 for (auto &inst : this->defineInsList_) {
160 inst.ins_->GetId(INDEX_0) = updatedLiteralArrayIdx;
161 }
162
163 for (auto &property : this->properties_) {
164 property->literalArrayIdx_ = updatedLiteralArrayIdx;
165 }
166 }
167
EnumerateMethods(const std::function<FunctionTraver> & callback)168 void panda::guard::Object::EnumerateMethods(const std::function<FunctionTraver> &callback)
169 {
170 for (const auto &property : this->properties_) {
171 if (property->method_) {
172 callback(property->method_.operator*());
173 }
174 }
175
176 for (auto &method : this->outerMethods_) {
177 callback(*method);
178 }
179 }
180
ExtractNames(std::set<std::string> & strings) const181 void panda::guard::Object::ExtractNames(std::set<std::string> &strings) const
182 {
183 for (const auto &property : this->properties_) {
184 property->ExtractNames(strings);
185 }
186
187 for (const auto &property : this->outerProperties_) {
188 property->ExtractNames(strings);
189 }
190
191 for (const auto &method : this->outerMethods_) {
192 method->ExtractNames(strings);
193 }
194 }
195
RefreshNeedUpdate()196 void panda::guard::Object::RefreshNeedUpdate()
197 {
198 this->needUpdate_ = true;
199 this->needUpdateName_ = TopLevelOptionEntity::NeedUpdate(*this);
200 }
201
Update()202 void panda::guard::Object::Update()
203 {
204 LOG(INFO, PANDAGUARD) << TAG << "object update for " << this->literalArrayIdx_ << " start";
205
206 if (this->contentNeedUpdate_ && this->needUpdateName_ && !this->name_.empty()) {
207 this->obfName_ = GuardContext::GetInstance()->GetNameMapping()->GetName(this->name_);
208 }
209
210 UpdateLiteralArrayIdx();
211
212 for (const auto &property : this->properties_) {
213 property->Obfuscate();
214 }
215
216 for (const auto &property : this->outerProperties_) {
217 property->Obfuscate();
218 }
219
220 for (const auto &method : this->outerMethods_) {
221 method->Obfuscate();
222 }
223
224 LOG(INFO, PANDAGUARD) << TAG << "object update for " << this->literalArrayIdx_ << " end";
225 }
226
WriteNameCache(const std::string & filePath)227 void panda::guard::Object::WriteNameCache(const std::string &filePath)
228 {
229 if (!this->obfuscated_ || !this->contentNeedUpdate_) {
230 return;
231 }
232
233 if (this->needUpdateName_ && !this->obfName_.empty()) {
234 GuardContext::GetInstance()->GetNameCache()->AddObfIdentifierName(filePath, this->GetNameCacheScope(),
235 this->obfName_);
236 }
237
238 for (const auto &property : this->properties_) {
239 property->WriteNameCache(filePath);
240 }
241
242 for (const auto &property : this->outerProperties_) {
243 property->WriteNameCache(filePath);
244 }
245 }
246
SetContentNeedUpdate(bool toUpdate)247 void panda::guard::Object::SetContentNeedUpdate(bool toUpdate)
248 {
249 this->contentNeedUpdate_ = toUpdate;
250 for (const auto &property : this->properties_) {
251 property->SetContentNeedUpdate(toUpdate);
252 }
253 for (const auto &method : this->outerMethods_) {
254 method->SetContentNeedUpdate(toUpdate);
255 }
256 }
257
SetExportAndRefreshNeedUpdate(bool isExport)258 void panda::guard::Object::SetExportAndRefreshNeedUpdate(bool isExport)
259 {
260 for (const auto &property : this->properties_) {
261 property->SetExportAndRefreshNeedUpdate(isExport);
262 }
263
264 for (const auto &property : this->outerProperties_) {
265 property->SetExportAndRefreshNeedUpdate(isExport);
266 }
267
268 for (const auto &method : this->outerMethods_) {
269 method->SetExportAndRefreshNeedUpdate(isExport);
270 }
271
272 Entity::SetExportAndRefreshNeedUpdate(isExport);
273 }
274
SetExportName(const std::string & exportName)275 void panda::guard::Object::SetExportName(const std::string &exportName)
276 {
277 this->name_ = exportName;
278 this->obfName_ = exportName;
279 this->SetNameCacheScope(exportName);
280 }
281