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
37 this->constructor_.defineInsList_ = this->defineInsList_;
38 this->constructor_.scope_ = this->scope_;
39 this->constructor_.Init();
40
41 // init class base info
42 this->name_ = this->constructor_.name_;
43 this->SetNameCacheScope(this->name_);
44 this->constructor_.export_ = this->moduleRecord_->IsExportVar(this->constructor_.name_);
45 this->export_ = this->constructor_.export_;
46
47 this->constructor_.Create();
48
49 auto &literalArrayTable = program_->prog_->literalarray_table;
50 auto it = literalArrayTable.find(this->literalArrayIdx_);
51 PANDA_GUARD_ASSERT_PRINT(it == literalArrayTable.end(), TAG, ErrorCode::GENERIC_ERROR,
52 "get bad literalArrayIdx:" << literalArrayIdx_);
53 CreateMethods(it->second);
54
55 LOG(INFO, PANDAGUARD) << TAG << "class build for " << this->constructor_.idx_ << " end";
56 }
57
GetMethodCnt() const58 size_t panda::guard::Class::GetMethodCnt() const
59 {
60 return this->methods_.size() + this->outerMethods_.size();
61 }
62
GetPropertyCnt() const63 size_t panda::guard::Class::GetPropertyCnt() const
64 {
65 size_t cnt = 0;
66 for (const auto &method : this->methods_) {
67 cnt += method.properties_.size();
68 }
69
70 for (const auto &method : this->outerMethods_) {
71 cnt += method.properties_.size();
72 }
73
74 return cnt;
75 }
76
ForEachMethodIns(const std::function<InsTraver> & callback)77 void panda::guard::Class::ForEachMethodIns(const std::function<InsTraver> &callback)
78 {
79 this->ForEachFunction([&callback](Function &func) { func.ForEachIns(callback); });
80 }
81
ForEachFunction(const std::function<FunctionTraver> & callback)82 void panda::guard::Class::ForEachFunction(const std::function<FunctionTraver> &callback)
83 {
84 callback(this->constructor_);
85 for (auto &method : this->methods_) {
86 callback(method);
87 }
88
89 for (auto &method : this->outerMethods_) {
90 callback(method);
91 }
92 }
93
ExtractNames(std::set<std::string> & strings) const94 void panda::guard::Class::ExtractNames(std::set<std::string> &strings) const
95 {
96 this->constructor_.ExtractNames(strings);
97
98 for (const auto &method : this->methods_) {
99 method.ExtractNames(strings);
100 }
101
102 for (const auto &method : this->outerMethods_) {
103 method.ExtractNames(strings);
104 }
105 }
106
CreateMethods(const pandasm::LiteralArray & literalArray)107 void panda::guard::Class::CreateMethods(const pandasm::LiteralArray &literalArray)
108 {
109 LOG(INFO, PANDAGUARD) << TAG << "literalArray size:" << literalArray.literals_.size();
110 size_t staticMethodIndexLiteralIndex = literalArray.literals_.size() - 1;
111 size_t methodItemCount = literalArray.literals_.size() - LITERAL_ITEM_LEN;
112 if (callRunTimeInst_) {
113 staticMethodIndexLiteralIndex -= CALL_RUNTIME_LITERAL_ITEM_LEN;
114 methodItemCount -= CALL_RUNTIME_LITERAL_ITEM_LEN;
115 }
116
117 const auto &staticMethodIndexLiteral = literalArray.literals_[staticMethodIndexLiteralIndex];
118 PANDA_GUARD_ASSERT_PRINT(staticMethodIndexLiteral.tag_ != panda::panda_file::LiteralTag::INTEGER, TAG,
119 ErrorCode::GENERIC_ERROR, "bad tag for staticMethodIndex");
120
121 const uint32_t staticMethodIndex = std::get<uint32_t>(staticMethodIndexLiteral.value_);
122 const size_t methodCount = methodItemCount / LITERAL_METHOD_GROUP_LEN;
123 LOG(INFO, PANDAGUARD) << TAG << "methodCount:" << methodCount;
124
125 for (size_t i = 0; i < methodCount; i++) {
126 CreateMethod(literalArray, i * LITERAL_METHOD_GROUP_LEN, i >= staticMethodIndex);
127 }
128 }
129
CreateMethod(const pandasm::LiteralArray & literalArray,size_t index,bool isStatic)130 void panda::guard::Class::CreateMethod(const pandasm::LiteralArray &literalArray, size_t index, bool isStatic)
131 {
132 const size_t methodNameLiteralIndex = index + 1;
133 const auto &methodNameLiteral = literalArray.literals_[methodNameLiteralIndex];
134 PANDA_GUARD_ASSERT_PRINT(methodNameLiteral.tag_ != panda::panda_file::LiteralTag::STRING, TAG,
135 ErrorCode::GENERIC_ERROR, "bad tag for methodName");
136
137 const std::string methodName = std::get<std::string>(methodNameLiteral.value_);
138 LOG(INFO, PANDAGUARD) << TAG << "methodName:" << methodName;
139
140 const size_t methodIdxLiteralIndex = methodNameLiteralIndex + LITERAL_ITEM_LEN;
141 PANDA_GUARD_ASSERT_PRINT(methodIdxLiteralIndex >= literalArray.literals_.size(), TAG, ErrorCode::GENERIC_ERROR,
142 "methodIdxLiteralIndex offset overflow");
143 const auto &[tag_, value_] = literalArray.literals_[methodIdxLiteralIndex];
144 PANDA_GUARD_ASSERT_PRINT(tag_ != panda::panda_file::LiteralTag::METHOD, TAG, ErrorCode::GENERIC_ERROR,
145 "bad tag for methodIdx");
146
147 const std::string methodIdx = std::get<std::string>(value_);
148 LOG(INFO, PANDAGUARD) << TAG << "methodIdx:" << methodIdx;
149
150 Method method(this->program_, methodIdx);
151 method.literalArrayIdx_ = this->literalArrayIdx_;
152 method.className_ = this->name_;
153 method.idxIndex_ = methodIdxLiteralIndex;
154 method.nameIndex_ = methodNameLiteralIndex;
155 method.static_ = isStatic;
156 method.scope_ = this->scope_;
157 method.export_ = this->export_;
158
159 method.Init();
160 method.Create();
161 PANDA_GUARD_ASSERT_PRINT(method.name_ != methodName, TAG, ErrorCode::GENERIC_ERROR,
162 "get different name for method:" << method.idx_);
163
164 this->methods_.push_back(method);
165 }
166
Update()167 void panda::guard::Class::Update()
168 {
169 LOG(INFO, PANDAGUARD) << TAG << "class update for " << this->name_ << " start";
170 this->constructor_.Obfuscate();
171 this->obfName_ = this->constructor_.obfName_;
172
173 for (auto &method : this->methods_) {
174 method.Obfuscate();
175 }
176
177 for (auto &method : this->outerMethods_) {
178 method.Obfuscate();
179 }
180
181 LOG(INFO, PANDAGUARD) << TAG << "class update for " << this->name_ << " end";
182 }
183
WriteNameCache(const std::string & filePath)184 void panda::guard::Class::WriteNameCache(const std::string &filePath)
185 {
186 if (!this->obfuscated) {
187 return;
188 }
189 this->WriteFileCache(filePath);
190 this->WritePropertyCache();
191
192 this->constructor_.WriteNameCache(filePath);
193 for (auto &property : this->constructor_.properties_) {
194 property.WriteNameCache(filePath);
195 }
196
197 for (auto &method : this->methods_) {
198 method.WriteNameCache(filePath);
199 }
200
201 for (auto &method : this->outerMethods_) {
202 method.WriteNameCache(filePath);
203 }
204 }
205
WriteFileCache(const std::string & filePath)206 void panda::guard::Class::WriteFileCache(const std::string &filePath)
207 {
208 if (!constructor_.nameNeedUpdate_) {
209 return;
210 }
211
212 GuardContext::GetInstance()->GetNameCache()->AddObfIdentifierName(filePath, this->GetNameCacheScope(),
213 this->obfName_);
214 }
215
WritePropertyCache()216 void panda::guard::Class::WritePropertyCache()
217 {
218 TopLevelOptionEntity::WritePropertyCache(*this);
219 }
220