• 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 "class.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 
24 namespace {
25 constexpr std::string_view TAG = "[Class]";
26 constexpr size_t LITERAL_ITEM_LEN = 2;               // 每两组元素表示一条数据tag-value
27 constexpr size_t LITERAL_METHOD_GROUP_LEN = 6;       // 每6组元素表示1个方法
28 constexpr size_t CALL_RUNTIME_LITERAL_ITEM_LEN = 2;  // 1组2个元素 记录运行信息
29 }  // namespace
30 
Build()31 void panda::guard::Class::Build()
32 {
33     LOG(INFO, PANDAGUARD) << TAG << "class build for " << this->constructor_.idx_ << " start";
34 
35     LOG(INFO, PANDAGUARD) << TAG << "isComponent:" << (this->component_ ? "true" : "false");
36     constructor_.node_ = this->node_;
37     constructor_.defineInsList_ = this->defineInsList_;
38     constructor_.scope_ = this->scope_;
39     constructor_.component_ = this->component_;
40     constructor_.Init();
41 
42     // init class base info
43     this->name_ = constructor_.name_;
44     this->SetNameCacheScope(this->name_);
45     constructor_.export_ = this->moduleRecord_->IsExportVar(constructor_.name_);
46     this->export_ = constructor_.export_;
47 
48     constructor_.Create();
49 
50     auto &literalArrayTable = program_->prog_->literalarray_table;
51     const auto it = literalArrayTable.find(this->literalArrayIdx_);
52     PANDA_GUARD_ASSERT_PRINT(it == literalArrayTable.end(), TAG, ErrorCode::GENERIC_ERROR,
53                              "get bad literalArrayIdx:" << literalArrayIdx_);
54     CreateMethods(it->second);
55 
56     LOG(INFO, PANDAGUARD) << TAG << "class build for " << this->constructor_.idx_ << " end";
57 }
58 
EnumerateMethodIns(const std::function<InsTraver> & callback)59 void panda::guard::Class::EnumerateMethodIns(const std::function<InsTraver> &callback)
60 {
61     this->EnumerateFunctions([&callback](Function &func) { func.EnumerateIns(callback); });
62 }
63 
EnumerateFunctions(const std::function<FunctionTraver> & callback)64 void panda::guard::Class::EnumerateFunctions(const std::function<FunctionTraver> &callback)
65 {
66     callback(this->constructor_);
67     for (auto &method : this->methods_) {
68         callback(*method);
69     }
70 
71     for (auto &method : this->outerMethods_) {
72         callback(*method);
73     }
74 }
75 
ExtractNames(std::set<std::string> & strings) const76 void panda::guard::Class::ExtractNames(std::set<std::string> &strings) const
77 {
78     this->constructor_.ExtractNames(strings);
79 
80     for (const auto &method : this->methods_) {
81         method->ExtractNames(strings);
82     }
83 
84     for (const auto &method : this->outerMethods_) {
85         method->ExtractNames(strings);
86     }
87 }
88 
CreateMethods(const pandasm::LiteralArray & literalArray)89 void panda::guard::Class::CreateMethods(const pandasm::LiteralArray &literalArray)
90 {
91     LOG(INFO, PANDAGUARD) << TAG << "literalArray size:" << literalArray.literals_.size();
92     size_t staticMethodIndexLiteralIndex = literalArray.literals_.size() - 1;
93     size_t methodItemCount = literalArray.literals_.size() - LITERAL_ITEM_LEN;
94     if (callRunTimeInst_) {
95         staticMethodIndexLiteralIndex -= CALL_RUNTIME_LITERAL_ITEM_LEN;
96         methodItemCount -= CALL_RUNTIME_LITERAL_ITEM_LEN;
97     }
98 
99     const auto &staticMethodIndexLiteral = literalArray.literals_[staticMethodIndexLiteralIndex];
100     PANDA_GUARD_ASSERT_PRINT(staticMethodIndexLiteral.tag_ != panda::panda_file::LiteralTag::INTEGER, TAG,
101                              ErrorCode::GENERIC_ERROR, "bad tag for staticMethodIndex");
102 
103     const uint32_t staticMethodIndex = std::get<uint32_t>(staticMethodIndexLiteral.value_);
104     const size_t methodCount = methodItemCount / LITERAL_METHOD_GROUP_LEN;
105     LOG(INFO, PANDAGUARD) << TAG << "methodCount:" << methodCount;
106 
107     for (size_t i = 0; i < methodCount; i++) {
108         CreateMethod(literalArray, i * LITERAL_METHOD_GROUP_LEN, i >= staticMethodIndex);
109     }
110 }
111 
CreateMethod(const pandasm::LiteralArray & literalArray,size_t index,bool isStatic)112 void panda::guard::Class::CreateMethod(const pandasm::LiteralArray &literalArray, size_t index, bool isStatic)
113 {
114     const size_t methodNameLiteralIndex = index + 1;
115     const auto &methodNameLiteral = literalArray.literals_[methodNameLiteralIndex];
116     PANDA_GUARD_ASSERT_PRINT(methodNameLiteral.tag_ != panda::panda_file::LiteralTag::STRING, TAG,
117                              ErrorCode::GENERIC_ERROR, "bad tag for methodName");
118 
119     const std::string methodName = std::get<std::string>(methodNameLiteral.value_);
120     LOG(INFO, PANDAGUARD) << TAG << "methodName:" << methodName;
121 
122     const size_t methodIdxLiteralIndex = methodNameLiteralIndex + LITERAL_ITEM_LEN;
123     PANDA_GUARD_ASSERT_PRINT(methodIdxLiteralIndex >= literalArray.literals_.size(), TAG, ErrorCode::GENERIC_ERROR,
124                              "methodIdxLiteralIndex offset overflow");
125     const auto &[tag_, value_] = literalArray.literals_[methodIdxLiteralIndex];
126     if (tag_ != panda_file::LiteralTag::METHOD) {
127         // if is callRuntime instruction, getter and setter method defined in literals
128         if (!callRunTimeInst_ || (tag_ != panda_file::LiteralTag::GETTER && tag_ != panda_file::LiteralTag::SETTER)) {
129             PANDA_GUARD_ABORT_PRINT(TAG, ErrorCode::GENERIC_ERROR, "bad tag for methodIdx");
130         }
131     }
132 
133     const std::string methodIdx = std::get<std::string>(value_);
134     LOG(INFO, PANDAGUARD) << TAG << "methodIdx:" << methodIdx;
135 
136     const auto method = std::make_shared<Method>(this->program_, methodIdx);
137     method->node_ = this->node_;
138     method->literalArrayIdx_ = this->literalArrayIdx_;
139     method->className_ = this->name_;
140     method->idxIndex_ = methodIdxLiteralIndex;
141     method->nameIndex_ = methodNameLiteralIndex;
142     method->static_ = isStatic;
143     method->scope_ = this->scope_;
144     method->export_ = this->export_;
145     method->component_ = this->component_;
146 
147     method->Init();
148     method->Create();
149     PANDA_GUARD_ASSERT_PRINT(method->name_ != methodName, TAG, ErrorCode::GENERIC_ERROR,
150                              "get different name for method:" << method->idx_);
151 
152     this->methods_.push_back(method);
153 }
154 
UpdateLiteralArrayIdx()155 void panda::guard::Class::UpdateLiteralArrayIdx()
156 {
157     if (!GuardContext::GetInstance()->GetGuardOptions()->IsFileNameObfEnabled()) {
158         return;
159     }
160 
161     const auto &it = this->program_->nodeTable_.find(this->constructor_.recordName_);
162     PANDA_GUARD_ASSERT_PRINT(it == this->program_->nodeTable_.end(), TAG, ErrorCode::GENERIC_ERROR,
163                              "not find node: " + this->constructor_.recordName_);
164     const auto &node = it->second;
165     if (node->name_ == node->obfName_) {
166         return;
167     }
168     std::string updatedLiteralArrayIdx = this->literalArrayIdx_;
169     updatedLiteralArrayIdx.replace(updatedLiteralArrayIdx.find(node->name_), node->name_.size(), node->obfName_);
170 
171     UpdateLiteralArrayTableIdx(this->literalArrayIdx_, updatedLiteralArrayIdx);
172 
173     this->literalArrayIdx_ = updatedLiteralArrayIdx;
174 
175     for (auto &inst : this->defineInsList_) {
176         inst.ins_->GetId(INDEX_1) = updatedLiteralArrayIdx;
177     }
178 
179     for (auto &method : this->methods_) {
180         method->literalArrayIdx_ = updatedLiteralArrayIdx;
181     }
182 }
183 
Update()184 void panda::guard::Class::Update()
185 {
186     LOG(INFO, PANDAGUARD) << TAG << "class update for " << this->name_ << " start";
187     this->constructor_.Obfuscate();
188     this->obfName_ = this->constructor_.obfName_;
189     UpdateLiteralArrayIdx();
190 
191     for (const auto &method : this->methods_) {
192         method->Obfuscate();
193     }
194 
195     for (const auto &method : this->outerMethods_) {
196         method->Obfuscate();
197     }
198 
199     LOG(INFO, PANDAGUARD) << TAG << "class update for " << this->name_ << " end";
200 }
201 
WriteNameCache(const std::string & filePath)202 void panda::guard::Class::WriteNameCache(const std::string &filePath)
203 {
204     if (!this->obfuscated_) {
205         return;
206     }
207     this->WriteFileCache(filePath);
208     this->WritePropertyCache();
209 
210     this->constructor_.WriteNameCache(filePath);
211     for (const auto &[_, property] : this->constructor_.propertyTable_) {
212         property->WriteNameCache(filePath);
213     }
214 
215     for (const auto &method : this->methods_) {
216         method->WriteNameCache(filePath);
217     }
218 
219     for (const auto &method : this->outerMethods_) {
220         method->WriteNameCache(filePath);
221     }
222 }
223 
WriteFileCache(const std::string & filePath)224 void panda::guard::Class::WriteFileCache(const std::string &filePath)
225 {
226     if (!this->constructor_.nameNeedUpdate_) {
227         return;
228     }
229 
230     GuardContext::GetInstance()->GetNameCache()->AddObfIdentifierName(filePath, this->GetNameCacheScope(),
231                                                                       this->obfName_);
232 }
233 
WritePropertyCache()234 void panda::guard::Class::WritePropertyCache()
235 {
236     TopLevelOptionEntity::WritePropertyCache(*this);
237 }
238