• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "node.h"
17 
18 #include "utils/logger.h"
19 
20 #include "configs/guard_context.h"
21 #include "graph_analyzer.h"
22 #include "program.h"
23 #include "util/assert_util.h"
24 #include "util/string_util.h"
25 
26 namespace {
27 using OpcodeList = std::vector<panda::pandasm::Opcode>;
28 
29 constexpr std::string_view TAG = "[Node]";
30 constexpr std::string_view ENTRY_FUNC_NAME = ".func_main_0";
31 constexpr std::string_view NORMALIZED_OHM_DELIMITER = "&";
32 constexpr std::string_view PATH_DELIMITER = "/";
33 constexpr std::string_view PACKAGE_MODULES_PREFIX = "pkg_modules";
34 constexpr std::string_view PKG_NAME_PREFIX = "pkgName@";
35 constexpr std::string_view SCOPE_NAMES_FIELD = "scopeNames";
36 constexpr std::string_view MODULE_RECORD_IDX_FIELD = "moduleRecordIdx";
37 constexpr std::string_view JSON_FILE_FIELD = "jsonFileContent";
38 constexpr size_t MAX_EXPORT_ITEM_LEN = 10000;
39 constexpr size_t STOBJBYVALUE_ACC_INDEX = 2;
40 
41 constexpr std::string_view OBJECT_PROPERTY_OBJECT = "Object";
42 constexpr std::string_view OBJECT_PROPERTY_PROTOTYPE = "prototype";
43 constexpr std::string_view OBJECT_PROPERTY_GETOWNPROPERTYDESCRIPTOR = "getOwnPropertyDescriptor";
44 constexpr std::string_view OBJECT_PROPERTY_DEFINEPROPERTY = "defineProperty";
45 constexpr size_t NAMESPACE_OWN_PARAM_REG_INDEX = 3;  // a3(this)
46 
47 const OpcodeList METHOD_NAME_DIRECT_LIST = {
48     panda::pandasm::Opcode::STOWNBYNAME,
49     panda::pandasm::Opcode::STOWNBYNAMEWITHNAMESET,
50 };
51 
52 const OpcodeList METHOD_NAME_INDIRECT_LIST = {
53     panda::pandasm::Opcode::DEFINEGETTERSETTERBYVALUE,
54     panda::pandasm::Opcode::STOWNBYVALUE,
55     panda::pandasm::Opcode::STOWNBYVALUEWITHNAMESET,
56 };
57 
InOpcodeList(const panda::guard::InstructionInfo & info,const OpcodeList & list)58 bool InOpcodeList(const panda::guard::InstructionInfo &info, const OpcodeList &list)
59 {
60     return std::any_of(list.begin(), list.end(), [&](const auto &elem) { return elem == info.ins_->opcode; });
61 }
62 
UpdateScopeNamesLiteralArray(panda::pandasm::LiteralArray & literalArray)63 void UpdateScopeNamesLiteralArray(panda::pandasm::LiteralArray &literalArray)
64 {
65     for (auto &literal : literalArray.literals_) {
66         if (!literal.IsStringValue()) {
67             continue;
68         }
69 
70         const auto &value = std::get<std::string>(literal.value_);
71         literal.value_ = panda::guard::GuardContext::GetInstance()->GetNameMapping()->GetName(value);
72     }
73 }
74 
75 template <typename T>
UpdateEntityNamespaceMemberExport(const std::string & entityIdx,const std::unordered_map<std::string,std::shared_ptr<T>> & map)76 void UpdateEntityNamespaceMemberExport(const std::string &entityIdx,
77                                        const std::unordered_map<std::string, std::shared_ptr<T>> &map)
78 {
79     PANDA_GUARD_ASSERT_PRINT(map.find(entityIdx) == map.end(), TAG, panda::guard::ErrorCode::GENERIC_ERROR,
80                              "invalid entityIdx:" << entityIdx);
81     const auto &entity = map.at(entityIdx);
82     LOG(INFO, PANDAGUARD) << TAG << "update namespace export for entity:" << entityIdx;
83     entity->SetExportAndRefreshNeedUpdate(true);
84 }
85 
IsRemoteHar(const std::string & name)86 bool IsRemoteHar(const std::string &name)
87 {
88     return panda::guard::StringUtil::IsPrefixMatched(name, PACKAGE_MODULES_PREFIX.data());
89 }
90 }  // namespace
91 
IsJsonFile(const pandasm::Record & record)92 bool panda::guard::Node::IsJsonFile(const pandasm::Record &record)
93 {
94     return std::any_of(record.field_list.begin(), record.field_list.end(),
95                        [](const auto &field) { return field.name == JSON_FILE_FIELD; });
96 }
97 
FindPkgName(const pandasm::Record & record,std::string & pkgName)98 bool panda::guard::Node::FindPkgName(const pandasm::Record &record, std::string &pkgName)
99 {
100     return std::any_of(
101         record.field_list.begin(), record.field_list.end(), [&](const panda::pandasm::Field &field) -> bool {
102             const bool found = field.name.rfind(PKG_NAME_PREFIX, 0) == 0;
103             if (found) {
104                 pkgName = field.name.substr(PKG_NAME_PREFIX.size(), field.name.size() - PKG_NAME_PREFIX.size());
105             }
106             return found;
107         });
108 }
109 
InitWithRecord(const pandasm::Record & record)110 void panda::guard::Node::InitWithRecord(const pandasm::Record &record)
111 {
112     if (IsJsonFile(record)) {
113         this->type_ = NodeType::JSON_FILE;
114         LOG(INFO, PANDAGUARD) << TAG << "json file:" << this->name_;
115         return;
116     }
117 
118     std::string pkgName;
119     if (FindPkgName(record, pkgName)) {
120         this->type_ = NodeType::SOURCE_FILE;
121         this->pkgName_ = pkgName;
122         LOG(INFO, PANDAGUARD) << TAG << "source file:" << this->name_;
123         return;
124     }
125 
126     if (record.metadata->IsAnnotation()) {
127         this->type_ = NodeType::ANNOTATION;
128         LOG(INFO, PANDAGUARD) << TAG << "annotation:" << this->name_;
129         return;
130     }
131 }
132 
Build()133 void panda::guard::Node::Build()
134 {
135     LOG(INFO, PANDAGUARD) << TAG << "node create for " << this->name_ << " start";
136 
137     this->sourceName_ = GuardContext::GetInstance()->GetGuardOptions()->GetSourceName(this->name_);
138     this->obfSourceName_ = this->sourceName_;
139     LOG(INFO, PANDAGUARD) << TAG << "node sourceName_ " << this->sourceName_;
140     this->isNormalizedOhmUrl_ = GuardContext::GetInstance()->GetGuardOptions()->IsUseNormalizedOhmUrl();
141     CreateFilePath();
142     this->filepath_.obfName = this->filepath_.name;
143     LOG(INFO, PANDAGUARD) << TAG << "pre part: " << this->filepath_.prePart;
144     LOG(INFO, PANDAGUARD) << TAG << "file path: " << this->filepath_.name;
145     LOG(INFO, PANDAGUARD) << TAG << "post part: " << this->filepath_.postPart;
146 
147     if (this->type_ == NodeType::SOURCE_FILE) {
148         moduleRecord_.Create();
149 
150         auto entryFunc = std::make_shared<Function>(this->program_, this->name_ + ENTRY_FUNC_NAME.data(), false);
151         entryFunc->Init();
152         entryFunc->Create();
153 
154         const auto &function = entryFunc->GetOriginFunction();
155         this->sourceFile_ = function.source_file;
156         this->obfSourceFile_ = function.source_file;
157 
158         entryFunc->EnumerateIns([&](const InstructionInfo &info) -> void { EnumerateIns(info, TOP_LEVEL); });
159 
160         this->functionTable_.emplace(entryFunc->idx_, entryFunc);
161     }
162 
163     this->ExtractNames();
164 
165     LOG(INFO, PANDAGUARD) << TAG << "node create for " << this->name_ << " end";
166 }
167 
GetRecord() const168 panda::pandasm::Record &panda::guard::Node::GetRecord() const
169 {
170     return this->program_->prog_->record_table.at(this->obfName_);
171 }
172 
EnumerateIns(const InstructionInfo & info,Scope scope)173 void panda::guard::Node::EnumerateIns(const InstructionInfo &info, Scope scope)
174 {
175     CreateFunction(info, scope);
176     CreateProperty(info);
177     CreateClass(info, scope);
178     CreateOuterMethod(info);
179     CreateObject(info, scope);
180     CreateObjectOuterProperty(info);
181     FindStLexVarName(info);
182     AddNameForExportObject(info);
183     if (GuardContext::GetInstance()->GetGuardOptions()->IsDecoratorObfEnabled()) {
184         CreateUiDecorator(info, scope);
185         CreateObjectDecoratorProperty(info);
186     }
187     UpdateExportForNamespaceMember(info);
188     CreateArray(info);
189 }
190 
CreateFunction(const InstructionInfo & info,Scope scope)191 void panda::guard::Node::CreateFunction(const InstructionInfo &info, Scope scope)
192 {
193     if (info.notEqualToOpcode(pandasm::Opcode::DEFINEFUNC)) {
194         return;
195     }
196 
197     const std::string idx = info.ins_->GetId(0);
198     if (this->functionTable_.find(idx) != this->functionTable_.end()) {
199         this->functionTable_.at(idx)->defineInsList_.push_back(info);
200         return;
201     }
202 
203     auto function = std::make_shared<Function>(this->program_, idx);
204     function->node_ = this;
205     function->scope_ = scope;
206     function->defineInsList_.push_back(info);
207     function->component_ = info.function_->component_;
208     function->Init();
209 
210     function->export_ = this->moduleRecord_.IsExportVar(function->name_);
211     function->Create();
212 
213     function->EnumerateIns([&](const InstructionInfo &insInfo) -> void { EnumerateIns(insInfo, FUNCTION); });
214 
215     this->functionTable_.emplace(function->idx_, function);
216 }
217 
218 /**
219  * e.g. class A {
220  *  constructor {
221  *    this.v1 = 1;
222  *
223  *    let obj = {};
224  *    obj.v2 = 2;
225  *  }
226  * }
227  * v1: property, bind function
228  * v2: variable property, bind object
229  */
CreateProperty(const InstructionInfo & info) const230 void panda::guard::Node::CreateProperty(const InstructionInfo &info) const
231 {
232     if (!Property::IsPropertyIns(info)) {
233         return;
234     }
235 
236     InstructionInfo nameInfo;
237     Property::GetPropertyNameInfo(info, nameInfo);
238     // if function is enum function, try to find property in acc
239     if (!nameInfo.IsValid() && info.function_->type_ == FunctionType::ENUM_FUNCTION) {
240         // e.g. this[0] = 'property'
241         LOG(INFO, PANDAGUARD) << TAG << "try to find property in acc";
242         GraphAnalyzer::GetLdaStr(info, nameInfo, STOBJBYVALUE_ACC_INDEX);
243     }
244 
245     if (!nameInfo.IsValid()) {
246         LOG(INFO, PANDAGUARD) << TAG << "invalid nameInfo:" << info.index_ << " " << info.ins_->ToString();
247         return;
248     }
249 
250     const std::string name = StringUtil::UnicodeEscape(nameInfo.ins_->GetId(0));
251     bool innerReg = info.IsInnerReg();
252     if (!innerReg && (info.function_->propertyTable_.find(name) != info.function_->propertyTable_.end())) {
253         info.function_->propertyTable_.at(name)->defineInsList_.emplace_back(info);
254         return;
255     }
256 
257     auto property = std::make_shared<Property>(this->program_, name);
258     property->defineInsList_.push_back(info);
259     property->nameInfo_ = nameInfo;
260     if (!innerReg) {
261         property->scope_ = this->scope_;
262         property->export_ = this->export_;
263         property->Create();
264 
265         LOG(INFO, PANDAGUARD) << TAG << "find property:" << property->name_;
266 
267         info.function_->propertyTable_.emplace(name, property);
268     } else {
269         property->scope_ = FUNCTION;
270         property->export_ = false;
271         property->Create();
272 
273         LOG(INFO, PANDAGUARD) << TAG << "find variable property:" << property->name_;
274 
275         info.function_->variableProperties_.push_back(property);
276     }
277 }
278 
CreateObjectDecoratorProperty(const InstructionInfo & info)279 void panda::guard::Node::CreateObjectDecoratorProperty(const InstructionInfo &info)
280 {
281     if (info.notEqualToOpcode(pandasm::Opcode::CALLTHIS2) && info.notEqualToOpcode(pandasm::Opcode::CALLTHIS3)) {
282         return;
283     }
284 
285     std::string callName = GraphAnalyzer::GetCallName(info);
286     if (callName != OBJECT_PROPERTY_GETOWNPROPERTYDESCRIPTOR && callName != OBJECT_PROPERTY_DEFINEPROPERTY) {
287         return;
288     }
289 
290     InstructionInfo objectParam;
291     GraphAnalyzer::GetCallTryLdGlobalByNameParam(info, INDEX_0, objectParam);
292     if (!objectParam.IsValid() || objectParam.ins_->GetId(0) != OBJECT_PROPERTY_OBJECT) {
293         return;
294     }
295 
296     InstructionInfo param1;
297     GraphAnalyzer::GetCallLdObjByNameParam(info, INDEX_1, param1);
298     if (!param1.IsValid() || param1.ins_->GetId(0) != OBJECT_PROPERTY_PROTOTYPE) {
299         return;
300     }
301 
302     InstructionInfo param2;
303     GraphAnalyzer::GetCallLdaStrParam(info, INDEX_2, param2);
304     if (!param2.IsValid()) {
305         return;
306     }
307 
308     const std::string name = StringUtil::UnicodeEscape(param2.ins_->GetId(0));
309     auto property = std::make_shared<Property>(this->program_, name);
310     property->scope_ = this->scope_;
311     property->export_ = this->export_;
312     property->defineInsList_.push_back(param2);
313     property->nameInfo_ = param2;
314     property->Create();
315     LOG(INFO, PANDAGUARD) << TAG << "find object decorator property:" << property->name_;
316     info.function_->objectDecoratorProperties_.push_back(property);
317 }
318 
CreateClass(const InstructionInfo & info,Scope scope)319 void panda::guard::Node::CreateClass(const InstructionInfo &info, Scope scope)
320 {
321     if (info.notEqualToOpcode(pandasm::Opcode::DEFINECLASSWITHBUFFER) &&
322         info.notEqualToOpcode(pandasm::Opcode::CALLRUNTIME_DEFINESENDABLECLASS)) {
323         return;
324     }
325 
326     const std::string idx = info.ins_->GetId(1);
327     if (this->classTable_.find(idx) != this->classTable_.end()) {
328         this->classTable_.at(idx)->defineInsList_.push_back(info);
329         return;
330     }
331 
332     auto clazz = std::make_shared<Class>(this->program_, info.ins_->GetId(0));
333     clazz->node_ = this;
334     clazz->moduleRecord_ = &this->moduleRecord_;
335     clazz->literalArrayIdx_ = idx;
336     clazz->defineInsList_.push_back(info);
337     if (GuardContext::GetInstance()->GetGuardOptions()->IsDecoratorObfEnabled()) {
338         clazz->component_ = GraphAnalyzer::IsComponentClass(info);
339     }
340     clazz->scope_ = scope;
341     if (info.ins_->opcode == pandasm::Opcode::CALLRUNTIME_DEFINESENDABLECLASS) {
342         clazz->callRunTimeInst_ = true;
343     }
344     clazz->Create();
345 
346     clazz->EnumerateMethodIns([&](const InstructionInfo &insInfo) -> void { EnumerateIns(insInfo, FUNCTION); });
347 
348     this->classTable_.emplace(clazz->literalArrayIdx_, clazz);
349 }
350 
CreateOuterMethod(const InstructionInfo & info)351 void panda::guard::Node::CreateOuterMethod(const InstructionInfo &info)
352 {
353     if (info.notEqualToOpcode(pandasm::Opcode::DEFINEMETHOD)) {
354         return;
355     }
356 
357     InstructionInfo defineInsInfo;
358     InstructionInfo nameInsInfo;
359     GraphAnalyzer::HandleDefineMethod(info, defineInsInfo, nameInsInfo);
360     PANDA_GUARD_ASSERT_PRINT(!defineInsInfo.IsValid(), TAG, ErrorCode::GENERIC_ERROR, "defineInsInfo is invalid");
361     // nameInsInfo maybe empty, therefore, there not check nameInsInfo. Instead, it is checked in actual use
362 
363     const std::string methodIdx = info.ins_->GetId(0);
364     std::string literalArrayIdx;
365     if (defineInsInfo.equalToOpcode(pandasm::Opcode::DEFINECLASSWITHBUFFER) ||
366         defineInsInfo.equalToOpcode(pandasm::Opcode::CALLRUNTIME_DEFINESENDABLECLASS)) {
367         literalArrayIdx = defineInsInfo.ins_->GetId(1);
368     } else {  // createobjectwithbuffer
369         literalArrayIdx = defineInsInfo.ins_->GetId(0);
370     }
371 
372     const auto outerMethod = std::make_shared<OuterMethod>(this->program_, methodIdx);
373     outerMethod->node_ = this;
374     outerMethod->defineInsList_.push_back(info);
375     GetMethodNameInfo(nameInsInfo, outerMethod->nameInfo_);
376     outerMethod->Init();
377 
378     if (this->classTable_.find(literalArrayIdx) != this->classTable_.end()) {
379         const auto &clazz = this->classTable_.at(literalArrayIdx);
380         outerMethod->className_ = clazz->name_;
381         outerMethod->export_ = clazz->export_;
382         outerMethod->scope_ = clazz->scope_;
383         outerMethod->component_ = clazz->component_;
384 
385         outerMethod->Create();
386 
387         LOG(INFO, PANDAGUARD) << TAG << "found method:" << methodIdx << " for class:" << clazz->name_;
388         clazz->outerMethods_.push_back(outerMethod);
389     } else if (this->objectTable_.find(literalArrayIdx) != this->objectTable_.end()) {
390         const auto &obj = this->objectTable_.at(literalArrayIdx);
391         outerMethod->export_ = obj->export_;
392         outerMethod->scope_ = obj->scope_;
393 
394         outerMethod->Create();
395 
396         LOG(INFO, PANDAGUARD) << TAG << "found method:" << methodIdx << " for obj:" << obj->literalArrayIdx_;
397         obj->outerMethods_.push_back(outerMethod);
398     } else {
399         PANDA_GUARD_ABORT_PRINT(TAG, ErrorCode::GENERIC_ERROR, "unexpect outer method for:" << literalArrayIdx);
400     }
401 
402     outerMethod->EnumerateIns([&](const InstructionInfo &insInfo) -> void { EnumerateIns(insInfo, FUNCTION); });
403 }
404 
CreateObject(const InstructionInfo & info,Scope scope)405 void panda::guard::Node::CreateObject(const InstructionInfo &info, Scope scope)
406 {
407     if (info.notEqualToOpcode(pandasm::Opcode::CREATEOBJECTWITHBUFFER)) {
408         return;
409     }
410 
411     const std::string idx = info.ins_->GetId(0);
412     if (this->objectTable_.find(idx) != this->objectTable_.end()) {
413         this->objectTable_.at(idx)->defineInsList_.push_back(info);
414         return;
415     }
416 
417     auto object = std::make_shared<Object>(this->program_, idx, this->name_);
418     LOG(INFO, PANDAGUARD) << TAG << "found record object:" << object->literalArrayIdx_;
419     object->node_ = this;
420     object->defineInsList_.push_back(info);
421     object->scope_ = scope;
422     object->Create();
423 
424     object->EnumerateMethods([&](Function &function) -> void {
425         function.EnumerateIns([&](const InstructionInfo &insInfo) -> void { EnumerateIns(insInfo, FUNCTION); });
426     });
427 
428     this->objectTable_.emplace(object->literalArrayIdx_, object);
429 }
430 
CreateObjectOuterProperty(const panda::guard::InstructionInfo & info)431 void panda::guard::Node::CreateObjectOuterProperty(const panda::guard::InstructionInfo &info)
432 {
433     if (info.notEqualToOpcode(pandasm::Opcode::DEFINEPROPERTYBYNAME)) {
434         return;
435     }
436 
437     InstructionInfo defineIns;
438     GraphAnalyzer::HandleDefineProperty(info, defineIns);
439     if (!defineIns.IsValid()) {
440         return;
441     }
442 
443     PANDA_GUARD_ASSERT_PRINT(defineIns.notEqualToOpcode(pandasm::Opcode::CREATEOBJECTWITHBUFFER), TAG,
444                              ErrorCode::GENERIC_ERROR, "unexpect related define ins");
445 
446     const std::string literalArrayIdx = defineIns.ins_->GetId(0);
447     PANDA_GUARD_ASSERT_PRINT(this->objectTable_.find(literalArrayIdx) == this->objectTable_.end(), TAG,
448                              ErrorCode::GENERIC_ERROR, "no record object for literalArrayIdx:" << literalArrayIdx);
449 
450     const auto &object = this->objectTable_.at(literalArrayIdx);
451     const auto property = std::make_shared<Property>(this->program_, info.ins_->GetId(0));
452     property->defineInsList_.push_back(info);
453     property->nameInfo_ = info;
454     property->export_ = object->export_;
455     property->scope_ = object->scope_;
456 
457     property->Create();
458 
459     object->outerProperties_.push_back(property);
460     LOG(INFO, PANDAGUARD) << TAG << "found object outer property:" << property->name_;
461 }
462 
AddNameForExportObject(const InstructionInfo & info)463 void panda::guard::Node::AddNameForExportObject(const InstructionInfo &info)
464 {
465     if (info.notEqualToOpcode(pandasm::Opcode::STMODULEVAR) &&
466         info.notEqualToOpcode(pandasm::Opcode::WIDE_STMODULEVAR)) {
467         return;
468     }
469 
470     InstructionInfo defineIns;
471     GraphAnalyzer::GetStModuleVarDefineIns(info, defineIns);
472     if (!defineIns.IsValid()) {
473         return;
474     }
475 
476     if (defineIns.notEqualToOpcode(pandasm::Opcode::CREATEOBJECTWITHBUFFER)) {
477         return;
478     }
479 
480     const int64_t index = std::get<int64_t>(info.ins_->GetImm(0));
481     PANDA_GUARD_ASSERT_PRINT(index < 0 || index > MAX_EXPORT_ITEM_LEN, TAG, ErrorCode::GENERIC_ERROR,
482                              "unexpect export item index:" << index);
483     const auto &exportName = this->moduleRecord_.GetLocalExportName(index);
484 
485     const auto &objectIdx = defineIns.ins_->GetId(0);
486     PANDA_GUARD_ASSERT_PRINT(this->objectTable_.find(objectIdx) == this->objectTable_.end(), TAG,
487                              ErrorCode::GENERIC_ERROR, "invalid objectIdx:" << objectIdx);
488     const auto &object = this->objectTable_.at(objectIdx);
489 
490     object->SetExportName(exportName);
491     object->SetExportAndRefreshNeedUpdate(true);
492 
493     LOG(INFO, PANDAGUARD) << TAG << "add export name:" << exportName << " for objectIdx:" << objectIdx;
494 }
495 
UpdateExportForNamespaceMember(const InstructionInfo & info) const496 void panda::guard::Node::UpdateExportForNamespaceMember(const InstructionInfo &info) const
497 {
498     if (info.notEqualToOpcode(pandasm::Opcode::STOBJBYNAME) ||
499         (info.function_->type_ != FunctionType::NAMESPACE_FUNCTION) ||
500         ((info.ins_->GetReg(0) - info.function_->regsNum_) != NAMESPACE_OWN_PARAM_REG_INDEX)) {
501         return;
502     }
503 
504     const auto propertyName = info.ins_->GetId(0);
505     PANDA_GUARD_ASSERT_PRINT(info.function_->propertyTable_.find(propertyName) == info.function_->propertyTable_.end(),
506                              TAG, ErrorCode::GENERIC_ERROR, "invalid propertyName:" << propertyName);
507     const auto &property = info.function_->propertyTable_.at(propertyName);
508     property->SetExportAndRefreshNeedUpdate(true);
509 
510     InstructionInfo defineIns;
511     GraphAnalyzer::GetStObjByNameDefineIns(info, defineIns);
512 
513     if (!defineIns.IsValid()) {
514         return;
515     }
516 
517     if (defineIns.equalToOpcode(pandasm::Opcode::DEFINEFUNC)) {
518         UpdateEntityNamespaceMemberExport(defineIns.ins_->GetId(0), this->functionTable_);
519     }
520 
521     if (defineIns.equalToOpcode(pandasm::Opcode::DEFINECLASSWITHBUFFER) ||
522         defineIns.equalToOpcode(pandasm::Opcode::CALLRUNTIME_DEFINESENDABLECLASS)) {
523         UpdateEntityNamespaceMemberExport(defineIns.ins_->GetId(1), this->classTable_);
524     }
525 
526     if (defineIns.equalToOpcode(pandasm::Opcode::CREATEOBJECTWITHBUFFER)) {
527         UpdateEntityNamespaceMemberExport(defineIns.ins_->GetId(0), this->objectTable_);
528     }
529 }
530 
CreateArray(const InstructionInfo & info)531 void panda::guard::Node::CreateArray(const InstructionInfo &info)
532 {
533     if (info.notEqualToOpcode(pandasm::Opcode::CREATEARRAYWITHBUFFER)) {
534         return;
535     }
536 
537     LOG(INFO, PANDAGUARD) << TAG << "found array:" << info.ins_->GetId(0);
538     auto array = std::make_shared<Array>(this->program_);
539     array->node_ = this;
540     array->nameInfo_ = info;
541     array->Create();
542 
543     this->arrays_.emplace_back(array);
544 }
545 
FindStLexVarName(const InstructionInfo & info)546 void panda::guard::Node::FindStLexVarName(const InstructionInfo &info)
547 {
548     if (info.notEqualToOpcode(pandasm::Opcode::STLEXVAR)) {
549         return;
550     }
551 
552     InstructionInfo outInfo;
553     GraphAnalyzer::GetLdaStr(info, outInfo);
554     if (!outInfo.IsValid()) {
555         return;
556     }
557 
558     LOG(INFO, PANDAGUARD) << TAG << "found stlexvar name:" << outInfo.ins_->GetId(0);
559     GuardContext::GetInstance()->GetNameMapping()->AddNameMapping(outInfo.ins_->GetId(0));
560 }
561 
CreateUiDecorator(const InstructionInfo & info,Scope scope)562 void panda::guard::Node::CreateUiDecorator(const InstructionInfo &info, Scope scope)
563 {
564     if (!UiDecorator::IsUiDecoratorIns(info, scope)) {
565         return;
566     }
567 
568     auto decorator = std::make_shared<UiDecorator>(this->program_, this->objectTable_);
569     decorator->scope_ = scope;
570     decorator->export_ = false;
571     decorator->baseInst_ = info;
572     decorator->Create();
573     if (!decorator->IsValidUiDecoratorType()) {
574         return;
575     }
576     this->uiDecorator_.emplace_back(decorator);
577 }
578 
CreateFilePath()579 void panda::guard::Node::CreateFilePath()
580 {
581     const auto &options = GuardContext::GetInstance()->GetGuardOptions();
582     if (!options->IsFileNameObfEnabled() || options->IsReservedRemoteHarPkgNames(this->pkgName_)) {
583         this->filepath_.name = this->name_;
584         return;
585     }
586 
587     if (this->isNormalizedOhmUrl_) {
588         CreateFilePathForNormalizedMode();
589     } else {
590         CreateFilePathForDefaultMode();
591     }
592 }
593 
CreateFilePathForDefaultMode()594 void panda::guard::Node::CreateFilePathForDefaultMode()
595 {
596     if (IsRemoteHar(this->name_)) {
597         if (this->type_ == NodeType::JSON_FILE) {
598             this->filepath_.name = this->name_;
599             return;
600         }
601         std::string prefix = pkgName_ + PATH_DELIMITER.data();
602         PANDA_GUARD_ASSERT_PRINT(!StringUtil::IsPrefixMatched(name_, prefix), TAG, ErrorCode::GENERIC_ERROR,
603                                  "invalid remote har prefix");
604         filepath_.prePart = std::move(prefix);
605 
606         filepath_.name = name_.substr(filepath_.prePart.size(), name_.size() - filepath_.prePart.size());
607         return;
608     }
609 
610     // format: bundleName/hapPkgName@pkgName/filepath
611     size_t startPos = name_.find_first_of(PATH_DELIMITER.data(), 0);
612     if (startPos == std::string::npos) {
613         filepath_.name = name_;
614         return;
615     }
616 
617     std::string toFound = pkgName_ + PATH_DELIMITER.data();
618     size_t foundPos = name_.find(toFound, startPos);
619     if (foundPos == std::string::npos) {
620         filepath_.name = name_;
621         return;
622     }
623 
624     foundPos += toFound.size();
625     filepath_.prePart = name_.substr(0, foundPos);
626     filepath_.name = name_.substr(foundPos, name_.size() - foundPos);
627 }
628 
CreateFilePathForNormalizedMode()629 void panda::guard::Node::CreateFilePathForNormalizedMode()
630 {
631     // [<bundle name>?]&<package name>/<file path>&[<version>?]
632     const size_t startPos = name_.find_first_of(NORMALIZED_OHM_DELIMITER.data(), 0);
633     const std::string prefix = this->type_ == NodeType::SOURCE_FILE
634                                    ? NORMALIZED_OHM_DELIMITER.data() + pkgName_ + PATH_DELIMITER.data()
635                                    : NORMALIZED_OHM_DELIMITER.data();
636 
637     PANDA_GUARD_ASSERT_PRINT(!StringUtil::IsPrefixMatched(name_, prefix, startPos), TAG, ErrorCode::GENERIC_ERROR,
638                              "invalid normalizedOhmUrl prefix");
639     size_t prefixEnd = startPos + prefix.size();
640     filepath_.prePart = name_.substr(0, prefixEnd);
641 
642     size_t filePathEnd = name_.find_first_of(NORMALIZED_OHM_DELIMITER.data(), prefixEnd);
643     PANDA_GUARD_ASSERT_PRINT(filePathEnd == std::string::npos, TAG, ErrorCode::GENERIC_ERROR,
644                              "invalid normalizedOhmUrl format");
645     filepath_.name = name_.substr(prefixEnd, filePathEnd - prefixEnd);
646 
647     filepath_.postPart = name_.substr(filePathEnd, name_.size() - filePathEnd);
648 }
649 
ExtractNames()650 void panda::guard::Node::ExtractNames()
651 {
652     moduleRecord_.ExtractNames(this->strings_);
653 
654     for (const auto &[_, function] : this->functionTable_) {
655         function->ExtractNames(this->strings_);
656     }
657 
658     for (const auto &[_, clazz] : this->classTable_) {
659         clazz->ExtractNames(this->strings_);
660     }
661 
662     for (const auto &[_, object] : this->objectTable_) {
663         object->ExtractNames(this->strings_);
664     }
665 
666     if (GuardContext::GetInstance()->GetGuardOptions()->IsDecoratorObfEnabled()) {
667         for (const auto &decorator : this->uiDecorator_) {
668             decorator->ExtractNames(this->strings_);
669         }
670     }
671 
672     auto parts = StringUtil::Split(filepath_.name, PATH_DELIMITER.data());
673     for (const auto &part : parts) {
674         this->strings_.emplace(part);
675     }
676 
677     GuardContext::GetInstance()->GetNameMapping()->AddReservedNames(this->strings_);
678 
679     LOG(INFO, PANDAGUARD) << TAG << "strings:";
680     for (const auto &str : this->strings_) {
681         LOG(INFO, PANDAGUARD) << TAG << str;
682     }
683 }
684 
RefreshNeedUpdate()685 void panda::guard::Node::RefreshNeedUpdate()
686 {
687     const auto &options = GuardContext::GetInstance()->GetGuardOptions();
688     if (options->IsUseNormalizedOhmUrl()) {
689         this->fileNameNeedUpdate_ = options->IsFileNameObfEnabled() && !options->IsReservedRemoteHarPkgNames(pkgName_);
690     } else {
691         this->fileNameNeedUpdate_ = options->IsFileNameObfEnabled() && !IsRemoteHar(this->name_);
692     }
693 
694     if (options->IsKeepPath(this->name_)) {
695         LOG(INFO, PANDAGUARD) << TAG << "found keep rule for:" << this->name_;
696         this->contentNeedUpdate_ = false;
697         GuardContext::GetInstance()->GetNameMapping()->AddNameMapping(this->strings_);
698     }
699 
700     for (auto &[_, object] : this->objectTable_) {
701         object->SetContentNeedUpdate(this->contentNeedUpdate_);
702     }
703 
704     this->needUpdate_ = this->fileNameNeedUpdate_ || this->contentNeedUpdate_;
705 }
706 
EnumerateFunctions(const std::function<FunctionTraver> & callback)707 void panda::guard::Node::EnumerateFunctions(const std::function<FunctionTraver> &callback)
708 {
709     for (auto &[_, function] : this->functionTable_) {
710         callback(*function);
711     }
712 
713     for (auto &[_, clazz] : this->classTable_) {
714         clazz->EnumerateFunctions(callback);
715     }
716 
717     for (auto &[_, object] : this->objectTable_) {
718         object->EnumerateMethods(callback);
719     }
720 }
721 
Update()722 void panda::guard::Node::Update()
723 {
724     LOG(INFO, PANDAGUARD) << TAG << "node update for " << this->name_ << " start";
725 
726     if (this->fileNameNeedUpdate_) {
727         this->UpdateFileNameDefine();
728     }
729 
730     // fileNameNeedUpdate_ || contentNeedUpdate_
731     for (auto &[_, function] : this->functionTable_) {
732         function->Obfuscate();
733         function->WriteNameCache(this->sourceName_);
734     }
735 
736     for (auto &[_, clazz] : this->classTable_) {
737         clazz->Obfuscate();
738         clazz->WriteNameCache(this->sourceName_);
739     }
740 
741     for (auto &[_, object] : this->objectTable_) {
742         object->Obfuscate();
743         object->WriteNameCache(this->sourceName_);
744     }
745 
746     for (const auto &annotation : this->annotations_) {
747         annotation->Obfuscate();
748         annotation->WriteNameCache(this->sourceName_);
749     }
750 
751     if (GuardContext::GetInstance()->GetGuardOptions()->IsDecoratorObfEnabled()) {
752         for (const auto &decorator : this->uiDecorator_) {
753             decorator->Obfuscate();
754             decorator->WriteNameCache(this->sourceName_);
755         }
756     }
757 
758     for (const auto &array : this->arrays_) {
759         array->Obfuscate();
760     }
761 
762     if (this->contentNeedUpdate_) {
763         moduleRecord_.Obfuscate();
764         moduleRecord_.WriteNameCache(this->sourceName_);
765     }
766 
767     this->UpdateScopeNames();
768     this->UpdateFieldsLiteralArrayIdx();
769 
770     this->WriteFileCache(this->sourceName_);
771 
772     LOG(INFO, PANDAGUARD) << TAG << "node update for " << this->name_ << " end";
773 }
774 
WriteFileCache(const std::string & filePath)775 void panda::guard::Node::WriteFileCache(const std::string &filePath)
776 {
777     GuardContext::GetInstance()->GetNameCache()->AddObfName(filePath, this->obfSourceName_);
778     GuardContext::GetInstance()->GetNameCache()->AddSourceFile(filePath, this->sourceFile_, this->obfSourceFile_);
779 }
780 
UpdateRecordTable()781 void panda::guard::Node::UpdateRecordTable()
782 {
783     auto entry = this->program_->prog_->record_table.extract(this->name_);
784     entry.key() = this->obfName_;
785     entry.mapped().name = this->obfName_;
786     if (!entry.mapped().source_file.empty()) {
787         this->UpdateSourceFile(entry.mapped().source_file);
788         entry.mapped().source_file = this->obfSourceFile_;
789     }
790     this->program_->prog_->record_table.insert(std::move(entry));
791 }
792 
UpdateFileNameDefine()793 void panda::guard::Node::UpdateFileNameDefine()
794 {
795     filepath_.obfName = GuardContext::GetInstance()->GetNameMapping()->GetFilePath(filepath_.name);
796     obfName_ = filepath_.prePart + filepath_.obfName + filepath_.postPart;
797     UpdateRecordTable();
798 
799     /* e.g.
800      *  sourceName_: entry/src/main/ets/entryability/EntryAbility.ets
801      *  filepath_.name: src/main/ets/entryability/EntryAbility
802      *  sourceNamePrePart: entry/
803      *  sourceNamePostPart: .ets
804      */
805     const auto &[sourceNamePrePart, sourceNamePostPart] = StringUtil::RSplitOnce(this->sourceName_, filepath_.name);
806     if (sourceNamePrePart.empty() && sourceNamePostPart.empty()) {
807         this->obfSourceName_ = obfName_;
808     } else {
809         this->obfSourceName_ = sourceNamePrePart + filepath_.obfName + sourceNamePostPart;
810     }
811 }
812 
UpdateFileNameReferences()813 void panda::guard::Node::UpdateFileNameReferences()
814 {
815     moduleRecord_.UpdateFileNameReferences();
816 }
817 
UpdateSourceFile(const std::string & file)818 void panda::guard::Node::UpdateSourceFile(const std::string &file)
819 {
820     PANDA_GUARD_ASSERT_PRINT(file != this->sourceFile_, TAG, ErrorCode::GENERIC_ERROR, "duplicate source file" << file);
821     if (this->sourceFileUpdated_) {
822         return;
823     }
824 
825     this->sourceFile_ = file;
826 
827     /* e.g.
828      *  file: entry|entry|1.0.0|src/main/ets/entryability/EntryAbility.ets
829      *  filepath_.name: src/main/ets/entryability/EntryAbility
830      *  prefix: entry|entry|1.0.0|
831      *  suffix: .ets
832      */
833     const auto &[prefix, suffix] = StringUtil::RSplitOnce(file, filepath_.name);
834     PANDA_GUARD_ASSERT_PRINT(file != filepath_.name && prefix.empty() && suffix.empty(), TAG, ErrorCode::GENERIC_ERROR,
835                              "invalid source file" << file << ",record: " << this->name_);
836     this->obfSourceFile_ = prefix + filepath_.obfName + suffix;
837     this->sourceFileUpdated_ = true;
838 
839     LOG(INFO, PANDAGUARD) << TAG << "source_file: " << this->sourceFile_;
840 }
841 
UpdateScopeNames() const842 void panda::guard::Node::UpdateScopeNames() const
843 {
844     LOG(INFO, PANDAGUARD) << TAG << "update scopeNames for:" << this->name_;
845     auto &record = this->GetRecord();
846     for (auto &it : record.field_list) {
847         if (it.name == SCOPE_NAMES_FIELD) {
848             const auto &literalArrayIdx = it.metadata->GetValue()->GetValue<std::string>();
849             LOG(INFO, PANDAGUARD) << TAG << "scopeNames literalArrayIdx:" << literalArrayIdx;
850             auto &literalArray = this->program_->prog_->literalarray_table.at(literalArrayIdx);
851             UpdateScopeNamesLiteralArray(literalArray);
852             break;
853         }
854     }
855 }
856 
UpdateFieldsLiteralArrayIdx()857 void panda::guard::Node::UpdateFieldsLiteralArrayIdx()
858 {
859     if (this->name_ == this->obfName_) {
860         return;
861     }
862 
863     LOG(INFO, PANDAGUARD) << "update fields literalArrayIdx for:" << this->name_;
864     auto &record = this->GetRecord();
865     for (auto &it : record.field_list) {
866         if (it.name == SCOPE_NAMES_FIELD || it.name == MODULE_RECORD_IDX_FIELD) {
867             const auto &literalArrayIdx = it.metadata->GetValue()->GetValue<std::string>();
868             LOG(INFO, PANDAGUARD) << TAG << "literalArrayIdx:" << literalArrayIdx;
869 
870             std::string updatedLiteralArrayIdx = literalArrayIdx;
871             updatedLiteralArrayIdx.replace(updatedLiteralArrayIdx.find(this->name_), this->name_.size(),
872                                            this->obfName_);
873             LOG(INFO, PANDAGUARD) << TAG << "updated literalArrayIdx:" << updatedLiteralArrayIdx;
874 
875             UpdateLiteralArrayTableIdx(literalArrayIdx, updatedLiteralArrayIdx);
876 
877             it.metadata->SetValue(
878                 pandasm::ScalarValue::Create<pandasm::Value::Type::LITERALARRAY>(updatedLiteralArrayIdx));
879 
880             if (it.name == MODULE_RECORD_IDX_FIELD) {
881                 this->moduleRecord_.UpdateLiteralArrayIdx(updatedLiteralArrayIdx);
882             }
883         }
884     }
885 }
886 
WriteNameCache()887 void panda::guard::Node::WriteNameCache()
888 {
889     this->WriteFileCache(this->sourceName_);
890 }
891 
GetMethodNameInfo(const InstructionInfo & info,InstructionInfo & nameInfo)892 void panda::guard::Node::GetMethodNameInfo(const InstructionInfo &info, InstructionInfo &nameInfo)
893 {
894     if (!info.IsValid()) {
895         return;
896     }
897 
898     if (InOpcodeList(info, METHOD_NAME_DIRECT_LIST)) {
899         nameInfo = info;
900     } else if (InOpcodeList(info, METHOD_NAME_INDIRECT_LIST)) {
901         GraphAnalyzer::GetLdaStr(info, nameInfo);
902     }
903 }
904