• 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 "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