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